In nwjs DOM seems to be empty when accessed from another module - javascript

I want to use modules in my nwjs app that use document, but it seems that they cannot properly access DOM of the main page.
Below you can find a simple test that shows the problem.
I have next files:
package.json
...
"main": "index.html"
...
index.html
<html>
<head>
<meta charset="utf-8" />
<title>test</title>
</head>
<body>
<div id="container_model_view" class="brd"></div>
<script>let exports = {};</script>
<script src="./main.js"></script>
</body>
</html>
main.ts (compiled into main.js before run)
import {getEl} from './mod_test';
console.log(document.getElementById("container_model_view"));
console.log(getEl());
mod_test.ts
export function getEl() {
return document.getElementById("container_model_view");
}
Output:
div#container_model_view.brd //access from main.ts - ok
null //access from mod_test.ts - fail
I found that I can bundle my main.js with rollup or webpack then it will work because the main module and the 'mod_test' module are merged into a single file. But I don't like that approach as I afraid it would impact the performance, not to mention it seems to be really unnecessary additional step in the assembling.

As it turned out, document pointing to the main page of the app exists only in browser context. require() loads modules in node context. Apparently, there's no way to specify in what context you want to load your module, it always will be node. Some ways to stay in browser context while loading module are described in the docs as follow:
Scripts loaded or embedded by traditional web ways, such as using
<script> element or jQuery’s $.getScript() or RequireJS, are running
in browser context.
Unfortunately I couldn't find a way to use any of the above natively with typescript.

Try mixing your contexts, so you can access DOM elements from server context:
Type this in package.json:
"chromium-args": "--mixed-context"

Related

How can I use an importmap when some of the js files don't include a valid relative reference symbol(s)?

I'm loading vtk.js from unpkg in a simple index.html file like so:
<html>
<body>
<script src="https://unpkg.com/#babel/polyfill#7.0.0/dist/polyfill.js"></script>
<script type="importmap">
{
"imports": {
"vtk/": "https://unpkg.com/vtk.js/"
}
}
</script>
<script type="module">
import 'vtk/Sources/favicon';
import 'vtk/Sources/Rendering/Profiles/Geometry';
</script>
</body>
</html>
When I load this in the browser I get an error in the console:
Uncaught TypeError: Failed to resolve module specifier "vtk.js/Sources/Rendering/OpenGL/Profiles/Geometry". Relative references must start with either "/", "./", or "../".
vtk/Sources/favicon imports without issue, but vtk/Sources/Rendering/Profiles/Geometry fails.
When I look at the vtk.js source I can see the problem, Geometry isn't actually doing anything other than importing two other modules and it doesn't have an appropriate relative reference before it.
import 'vtk.js/Sources/Rendering/OpenGL/Profiles/Geometry';
import 'vtk.js/Sources/Rendering/WebGPU/Profiles/Geometry';
Since these files are not under my control I can't modify them to have the relative url prefix. Is there another option?
Note: I know I really should be actually bundling the package with my app, even vtk.js docs say so but they also seem to indicate that using unpkg is possible and may be useful for fast prototyping.
At this point I'll just install the package so I don't waste more time on it...but I'm still curious how I could get this working with the hosted vtk.js (or if it isn't possible)?
Thanks!

Can RXJS run without a server on (client side)?

Ok so this will seem silly but please help if you can.
I want to start using RXJS.
as opposed to vanilla javascript it doesnt seem to work by just downloading it and then importing from the local source file.
(simple example):
HTML:
<head>
<meta charset="utf-8">
</head>
<body>
<script src="app.ts"></script>
</body>
app.ts:
// RxJS v6+
import { interval } from 'rxjs';
import { sample } from 'rxjs/operators';
I get an error though that this is a valid object (obviously because there is no rxjs loaded via the initial html page as a script)
QUESTION: What is a good way to load rxjs assuming that I want to create an offline site that the user downloads once and then uses the resources importing them from this local file (not all at once obviously) for route?
** I dont want to run a server on client side though if possible**
Thanks,
Alex
HTML:
<head>
<meta charset="utf-8">
</head>
<body>
<script src="app.ts"></script>
</body>
app.ts:
// RxJS v6+
import { interval } from 'rxjs';
import { sample } from 'rxjs/operators';
First, typescript doesn't run natively in the browser. You'll have to transpile it by configuring a tsconfig.json, or using babel with the typescript-preset.
I recommend changing your file extensions to js for starters. Secondly, I recommend using something simple to bundle your ES6 imports into something the browser can read, like Parcel. If you choose to use native ES6 modules, you'll need to link to RXJS in your index.html file, and whatever dependencies it may require, rather than using a package.json.
All that said, I recommend getting your feet wet with Parcel. It will generate a single js file that is the sum of all of your dependencies. And that js file can be referenced in the script tag of your index.html file.
Here's their Getting Started guide:
https://parceljs.org/getting_started.html
You should take a look at a framework like electron. You can create executable applications for OS like windows or iOS with that. There are some initial scaffolds out there which you can easily find via google. Start with them and add rxjs with npm or yarn.
Nothing can stop you, keep ahead.
( I had make a electron application in the past and it works better then expected )

How to export a require assigned to a variable?

I'm doing the following to make this require to become visible in <app></app>
index.html:
<script>
var electron = require('electron')
</script>
<app></app>
<script src="bundle.js"></script>
App.vue:
const ipc = electron.ipcRenderer
console.log(ipc)
But I get un-used and un-defined var errors with ESLint, so I decided to do this:
requires.js:
var electron = require('electron')
exports.electron = electron
index.html:
<script src="requires.js"></script>
</head>
<body>
<app></app>
<script src="bundle.js"></script>
But now I get this error: requires.js:3 Uncaught ReferenceError: exports is not defined.
What the correct way to export and import the electron require?
Note: requiring electron directly in App.vue doesn't work. You can only require electron in index.html
Full example: https://github.com/alexcheninfo/vue-electron-simple
What you seem to be trying to do here is define electron as a global variable; for that to work you can set window.electron = require('electron') in your index.html in the first example. (It will be available in you bundle.js)
However, using globals for this bad practice and not necessary. What you should do, is just use require in your code. You say this doesn't work: the reason why it doesn't is probably that you're using webpack or something similar to create bundle.js. Furthermore, you probably run the bundling process in Node and not in Electron, therefore require('electron') does not work as expected. Note that it works in your index.html which is not part of the bundle.
If you want to continue to use this setup, you could rename Electron's require to distinguish between the require resolved during bundling and the require resolved at runtime. In other words, window.electronRequire = require in the script tag of index.html and then use electronRequire('electron') in your code.
Having said that, why bundle everything in the first place? Electron has full Node integration so you can use regular Node modules; the files are not sent via HTTP either so there is little to gain from bundling everything into one file.

sharing code from a browserify file

I have a JavaScript library that is using Browserify to keep the code modular.
The library itself uses basic Browserify functionality to require other JS files.
myLibrary.js
var utils = require('helpers/utils.js')
console.log("Hello, I am logging from myLibrary")
function my_api(){
utils.someFn()
}
I'm using Gulp to browserify myLibrary.js and it is being built correctly, I've put several logs into myLibrary.js and when I load the file in an example html file I can see the logs.
I have an example index.html file that uses myLibrary.js and I expect my_api to be accessible from index.html.
index.html
<script src="my_url/myLibrary.js"></script>
<script src="app.js"></script>
app.js
my_api()
Chrome console
Hello I am logging from myLibrary (myLibrary.js)
Uncaught ReferenceError: my_api is not defined (app.js)
I've tried to defer the loading of app.js until myLibrary.js was ready but I'm beginning that that is not the problem.
You need to export your public functions.
module.exports = {my_api: my_api};
The solution I ended up using was to expose one global object that contains all the methods I want to expose through myLibrary using the window object.
myLibrary.js is requiring a utility function file and using them as helpers in the methods that I want to expose.
myLibrary.js
var util = require("utils.js")
window.myGlobalObjWithAUniqueName = {
myFn: function(){
util.someHelper()
}
}
Then I use Browserify to create the new browserified_myLibrary.js and use its methods in any file I want to load it in.
index.html
<script src="browserified_myLibrary.js"></script>
<script src="app.js"></script>
app.js
myGlobalObjWithAUniqueName.myFn()
Not sure if this is the best way of doing this but this seems to suit my need to modularize a client side library and use it without having to use Browserify every time I use it.
You may also want to look into the --standalone option exposed by browserify:
When opts.standalone is a non-empty string, a standalone module is created with that name and a umd wrapper. You can use namespaces in the standalone global export using a . in the string name as a separator, for example 'A.B.C'. The global export will be sanitized and camel cased.
From https://github.com/substack/node-browserify#usage

Basic requirejs concept needed to make work musicjson package

I'd like to use the musicjson.js package that helps to convert musicXML files into json notation, looking if it's a good way to import for example exported musicXML Finale scores into a browser playing with the Fermata/VexFlow class.
https://github.com/saebekassebil/musicjson
The thing is that this module works with require (calling for
nodes packages like fs) and I'm just a newbee in requirejs...Even if I spent few time in understanding the tutorial in the website, I don't still get how to solve this kind of basic problem when the dependencies of my musicjson.js need to be called like :
var xmldom = require('flat-xmldom'),
fs = require('fs'),
path = require('path'),
util = require('util');
My index.php page does the classic require call:
<!DOCTYPE html>
<head>
<!-- javascript head -->
<!-- REQUIRE -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
</head>
<body>
</body>
</html>
In my scripts/main.js, I'd like to do simply what it is told from musicjon :
var music = require('musicjson');
music.musicJSON(xml, function(err, json) {
// Do something with the MusicJSON data
});
I putted also, in the same directory scripts/, the flat-xmldom folder, fs.js, path.js, util.js
When I do this, I've just obtain this classic error of :
*Error: Module name "musicjson" has not been loaded yet for context: _. Use require([])*
...That looks like a common error referenced in the requirejs website,
but if I try things that I guess it should be written, I get a bit lost to determine where is the fundamental conceptual mistake here :
require.config({
baseUrl: '/scripts/',
paths: {
flatxmldom:'./flat-xmldom/__package__',
fs: 'fs',
path:'path',
util:'util',
musicjson: 'musicjson'
}
});
require(['flatxmldom','fs','path','util','musicjson'],function(flatxmldom,fs,path,util,musicjson){})
Error returned in this case for example :
*Module name "fs" has not been loaded yet for context: _. Use require([])*
Thanks a lot for your attention.
So, this is not a RequireJS problem per-se. The package you want to use is a Node.js package. It is intended to run in node (a server/desktop execution environment for JavaScript). It cannot/will not run in web page in a browser.
The packages it is trying to use (fs in particular) provide access to system resources such as the file system. Node provides these packages as part of its core libraries to any package that runs in node. A browser is specifically designed for security reasons never to allow direct access to such resources to any code that run in the browser because who knows where it came from or might try to do.
I haven't really tried to do this myself, but browserify (alternative to requirejs) claims that it will allow you to use any node package in your application.
If musicjson is at the heart of what your app should achieve and requirejs is a small step on the way to getting there, you could try your luck with browserify instead.

Categories

Resources