Can't require node modules in JS files in svelte electron - javascript

I'm using electron with svelte as my frontend framework.
I have JS files that contain functions used by my svelte components.
When I try to import a node module using require - it returns an empty object.
When I use require inside a svelte component it works fine. (I've set nodeIntegration: true in my electron.js file).
How could I fix this?
EDIT: An example:
<!--SvelteComponent.svelte-->
<script>
import {func} from "./jsFile";
</script>
//jsFile.js
const fs = require("fs"); // This require returns an empty object
export function func {...}
I also get a Rollup warning: (!) Plugin node-resolve: preferring built-in module 'fs' over local alternative at 'fs', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning

It turns out I should have used window.require instead of require

Here's a fragment of a working svelte component from my application. All imported or required objects just work fine.
<script>
import '../../../node_modules/materialize-css/dist/css/materialize.css';
import '../../../css/material-icons-svelte.css'; // we'd have to adjust the font paths!! check extra.css
import '../../../node_modules/codemirror/lib/codemirror.css';
import '../../../node_modules/materialize-css/dist/js/materialize.js';
const {getState, getStore} = require('../../../dist/store/store.renderer');
const {ipcRenderer} = require('electron');
const _ = require('lodash');
Edit
I added this to my App.svelte component, that I use on a svelte app with electron and, well, it works. Prints the fs object to the console and it's not empty
const fs = require('fs')
console.log(fs);
nodeIntegration is set to true, this my index.html:
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<link rel='stylesheet' href='../../../css/global.css'>
<link rel='stylesheet' href='../../../dist/app/myapp/extra.css'>
<link rel='stylesheet' href='../../../dist/app/myapp/bundle.css'>
</head>
<body class="grey lighten-4">
<script src='../../../dist/app/myapp/bundle.js'></script>
</body>
</html>
And I'm on electron 8.2.5

Related

Getting 'ReferenceError: not defined' when using import/export modules

I've got and exportUserList.js, importUserList.js and the main.js files. The main.js file contains already defined 2 variables which I want to log to the console and I also want to log the imported user variable from the main.js file. But I keep on receiving 'user not defined'. I've used the suggested window option, but it is not passing on the variable. Can this be corrected?
this is the html:
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet" />
<title></title>
<style>
</style>
<head>
</head>
<body>
<script type="module" src="/importUserList.js"></script>
<script type="text/javascript" src="/main.js"></script>
</body>
this is the export exportUserList.js :
export const user = 'first user'
this is the import importUserList.js :
import {user} from './exportList.js'
console.log(user)
window.user = user
and this is the main.js:
let names = 'mark'
let numbers = 10
console.log(names)
console.log(numbers)
console.log(user)
Option 1: defer your main script, because modules defer by default, and so because your main script doesn't it gets runs before the module has.
However, that's the bad option, and you shouldn't put that into practice because that keeps you using modules in completely the wrong way. Never do that.
The much better solution is to make your main.js a module and then tell it to import what it needs in order to run. You don't load modules only to bind their data onto globalThis (window in this case), the whole point of modules is to keep code contained, so that whatever needs a module's exports, can just import that as needed. You use modules to not pollute the global scope =)
So: remove that importUserList.js and instead put the import in your main script:
import {user} from './exportList.js'
let names = 'mark'
let numbers = 10
console.log(names)
console.log(numbers)
console.log(user)
And then load your main script as a module with:
<script type="module" src="/main.js"></script>
And then of course remember that modules always load deferred.
Basically: if you're using modules, use modules "all the way down".

How do I import modules in a project using pyodide without errors?

Whenever I import python modules in a pyodide, it gives this error.
pyodide.js:108 Invalid package name or URI
I am not sure how to properly import modules,
I have tried this which was mentioned in the docs.
pyodide.loadPackage('<module address>')
(this returns a promise on whoes resolution I run this method)
pyodide.runPython('
<python code here>
')
Upon execution, I get the error mentioned above.
Javascript Code:
<html>
<head>
<script type="text/javascript">
// set the pyodide files URL (packages.json, pyodide.asm.data etc)
window.languagePluginUrl = 'https://pyodide-cdn2.iodide.io/v0.15.0/full/';
</script>
<script src="https://pyodide-cdn2.iodide.io/v0.15.0/full/pyodide.js"></script>
</head>
<body>
Pyodide test page <br>
Open your browser console to see pyodide output
<script type="text/javascript">
languagePluginLoader.then(function () {
pyodide.loadPackage('<address>').then(() => {
console.log(pyodide.runPython('
import sys
from <my package> import *
sys.version
'));
console.log(pyodide.runPython('print(1 + 2)'));
});
});
</script>
</body>
</html>
There is a chance that this question might be unclear, but please let me know if you have trouble understanding something.
Also, the string passed in the runPython() method is the python code, just to avoid confusion.
I even tried uploading the module to a server as the docs mentioned a URL using the HTTP protocol, was pretty stupid trying this but I did.
Docs: https://pyodide.readthedocs.io/en/latest/using_pyodide_from_javascript.html#loading-packages
Update: Pyodide v0.21.0
Starting with Pyodide 0.18.0, runPythonAsync does not automatically load packages, so loadPackagesFromImports should be called beforehand.
So, to import a third-party package like numpy we have two options: we can either pre-load required packages manually and then import them in Python
// JS
await pyodide.loadPackage('numpy');
// numpy is now available
pyodide.runPython('import numpy as np')
console.log(pyodide.runPython('np.ones((3, 3)))').toJs())
or we can use the loadPackagesFromImports function that will automatically download all packages that the code snippet imports:
// JS
let python_code = `
import numpy as np
np.ones((3,3))
`
(async () => { // enable await
await pyodide.loadPackagesFromImports(python_code)
let result = await pyodide.runPythonAsync(python_code)
console.log(result.toJs())
})() // call the function immediately
More examples can be found here
(async () => { // enable await
let python_code = `
import numpy as np
np.ones((3,3))
`
let pyodide = await loadPyodide();
await pyodide.loadPackagesFromImports(python_code)
console.log(pyodide.runPython(python_code).toJs())
})() // call the function immediately
<script src="https://pyodide-cdn2.iodide.io/v0.21.0/full/pyodide.js"></script>
Note also, that starting with version 0.17, Pyodide uses JsProxy for non-JS datatypes. So, before printing the results, it has to be converted using toJs.
Old answer (related to Pyodide v0.15.0)
It is not clear what you are passing as <address> in pyodide.loadPackage('<address>'), but it should just be the package name (e.g. numpy).
Also, note that Pyodide currently supports a limited number of packages. Check out this tutorial on it for more details.
If you want to import a third-party package like numpy there are two options: you can either pre-load required packages manually and then import them in Python using pyodide.loadPackage and pyodide.runPython functions:
pyodide.loadPackage('numpy').then(() => {
// numpy is now available
pyodide.runPython('import numpy as np')
console.log(pyodide.runPython('np.ones((3, 3)))'))
})
Or you can use pyodide.runPythonAsync function that will automatically download all packages that the code snippet imports.
Here is the minimal example for pyodide.runPythonAsync
let python_code = `
import numpy as np
np.ones((3,3))
`
// init environment, then run python code
languagePluginLoader.then(() => {
pyodide.runPythonAsync(python_code).then(output => alert(output))
})
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.21.0/full/pyodide.js"></script>
</head>
<body>
</body>
</html>

how to get path for import of javascript from file

I have a file where i defined the absolute path of directory.
Ex : script=/absolutepath/scripts
utility=/absolutepath/utility
I want to use "script"/"utility" instead of absolute path in other javascript files.How i can do this.
What i want :
import random from "script/random.js"
instead of
import random from "/absolutepath/scripts/random.js"
PS :I am using k6 load generating framework which doesn't support node modules.
You currently can't do that in k6 v0.26.0.
Import paths like that are reserved for internal k6 modules (e.g. k6/http) and "magic" remote import URLs (e.g. import from github.com/loadimpact/k6/samples/thresholds_readme_example.js instead of https://raw.githubusercontent.com/loadimpact/k6/master/samples/thresholds_readme_example.js, and we're trying to softly discourage this). You can't define your own, you either have to use relative paths or absolute paths when importing your own JS files.
You could try using importmaps.
Inside your index.html:
<html lang="en">
<head>
<script type="importmaps">
{
"imports": {
"random": "/absolutePath/scripts/random.js"
}
}
</script>
<script type="module" src="app.js"></script>
</head>
</html>
You can now import your module from ANYWHERE
import random from 'random'

Using redux-promise-middleware with web component tester

I have an import called redux-scripts
<link rel="import" href="../config.html">
<script src="../../node_modules/redux/dist/redux.min.js"></script>
<script src="../../bower_components/amazon-cognito-identity-js/dist/aws-cognito-sdk.min.js"></script>
<script src="../../bower_components/amazon-cognito-identity-js/dist/amazon-cognito-identity.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux-promise-middleware/4.4.1/redux-promise-middleware.min.js"></script>
<script src="./redux-promises.js"></script>
Which I import at the top of redux-mixin.html
<link rel="import" href="../../bower_components/polymer-redux/polymer-redux.html">
<script src="../../bower_components/aws-sdk/dist/aws-sdk.min.js"></script>
<link rel="import" href="redux-scripts.html">
<script type="module" src="./index.js"></script>
<script nomodule src="./bundle.js"></script>
Runs like a charm in Chrome and firefox, but when it comes to web component tester:
redux-store.js:22 Uncaught ReferenceError: ReduxPromiseMiddleware is not defined
at redux-store.js:22
Which is referring to
import programs from './programs/programsReducer.js';
import videos from './videos/videosReducer.js';
import video from './video/videoReducer.js';
const rootReducer = Redux.combineReducers({
programs,
videos,
video,
});
// Setup a Redux store
const initialState = {
viewSpecificToolbar: 'videos',
};
const store = Redux.createStore(
rootReducer,
initialState,
// The best part 8)
Redux.compose(
Redux.applyMiddleware(ReduxPromiseMiddleware.default()),
window.devToolsExtension ? window.devToolsExtension() : (v) => v
)
);
export {store};
I've implemented a partial workaround by adding this to the top of redux-store.js
const scripts = Polymer.ResolveUrl.resolveUrl('./redux-scripts.html');
Polymer.importHref(scripts, null, null, false);
But it's not super satisfying, as it causes many errors when running tests, and not all of the test suites run.
Another solution was to add the redux-scripts.html import to all test files, however, a better solution was attained by altering the redux-promise-middleware library. In version 4.4.2, the import statement in index.js now points to the relative path ./isPromise.js with file extension. With that in place, I can import promiseMiddleware from '../../node_modules/redux-promise-middleware/dist/es/index.js' in redux-store.js and we're golden.

Unexpected token import on Electron app

I have built an app using GitHub's Electron. I am using the recommended way of loading modules, the ES6 syntax of:
import os from 'os'
After downloading the boilerplate the app is working fine. I have been able to import scripts in the background.js file without issue. Below is how I am loading my custom module:
import { loadDb } from './assets/scripts/database.js';
However, when I open a new browser window (clipboard.html) within Electron I am then loading a JavaScript file (clipboard.js) which in turn tries to import modules. At this point I am getting an Unexpected token import error.
My clipboard.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Electron Boilerplate</title>
<link href="./stylesheets/main.css" rel="stylesheet" type="text/css">
<script>
window.$ = window.jQuery = require('./assets/scripts/jquery-1.12.1.min.js');
</script>
<script src="./assets/scripts/clipboard.js"></script>
</head>
<body class="clipboard">[...]</body></html>
My clipboard.js file:
import { remote } from 'electron'; // native electron module
import { loadDb } from './assets/scripts/database.js';
const electron = require('electron');
document.addEventListener('DOMContentLoaded', function () {
var db = loadDb();
db.find({ type: 'text/plain' }, function (err, docs) {
var docsjson = JSON.stringify(docs);
console.log(docsjson);
});
});
Just to re-iterate, the same code is used within app.html, which is my app's main window, and this does not error.
It feels like the main window is initialising something that my clipboard.html window isn't (perhaps 'Rollup'?), but there's nothing explicit within my app's code to suggest this.
You need to run clipboard.js through rollup first. Rollup parses the import statements. You have to modify tasks/build/build.js to do that.
var bundleApplication = function () {
return Q.all([
bundle(srcDir.path('background.js'), destDir.path('background.js')),
bundle(srcDir.path('clipboard.js'), destDir.path('clipboard.js')), // Add this line
bundle(srcDir.path('app.js'), destDir.path('app.js')),
]);
};
#user104317 got it right, clipboard.js just didn't get "compiled" by rollup.
Just wanted to add that in your case, it should have been:
var bundleApplication = function () {
return Q.all([
bundle(srcDir.path('background.js'), destDir.path('background.js')),
bundle(srcDir.path('app.js'), destDir.path('app.js')),
bundle(srcDir.path('assets/scripts/clipboard.js'), destDir.path('assets/scripts/clipboard.js')),
]);
};
Then you could have left it at ./assets/scripts/clipboard.js.
If you end up having a lot of independent js files (you shouldn't if you're building a SPA), consider listing them automatically, like done in ./tasks/build/generate_spec_imports.js

Categories