Typically, in an Electron app, you can require node modules from both the main process and the renderer process:
var myModule = require('my-module');
However, this doesn't seem to work if the page was loaded via HTTP instead of from the local filesystem. In other words, if I open a window like this:
win.loadURL(`file://${__dirname}/index.html`);
I can require a node module without problems. But if I instead open a window like this:
win.loadURL(`http://localhost:1234/index.html`);
I no longer can require node modules inside my web page - I get Uncaught Error: Cannot find module 'my-module' in the web page's console. Is there any way to use node modules in an Electron page that was served over HTTP?
A little context: My company is building an application that needs the ability to be hosted as a web application and inside an Electron shell. To make this simpler and consistent across both environments, my Electron app starts a local web server and opens the app hosted at http://localhost:1234. Now I'd like the ability to add spell checking/spelling suggestions into the application using electron-spell-check-provider. This module needs to be imported and initialized inside the renderer process, so I'm trying to require('electron-spell-check-provider') inside my web page, but this fails with the Cannot find module error.
Finally figured this out. In the main process, figure out the absolute path to the node_modules directory, as in:
var nodeModDir = require.resolve('some-valid-module');
var dirnm = 'node_modules';
var pos = nodeModDir.lastIndexOf(dirnm);
if(pos != -1)
nodeModDir = nodeModDir.substr(0, pos+dirnm.length+1);
Now get this path to the renderer process via some IPC. Finally, in the renderer you can now require using an absolute path:
var mymod = require(nodeModDir+'some-valid-module');
Works perfectly for me with electron 1.6.7.
You can add a preload-script which adds a property to the global/window variable. I named mine appRoot. appRoot just has the __dirname value of the preload-script. You then have to go from the folder of the preload-script to your module. I simply use path.join() to make it clean.
This is similar to #logidelic's approach, but without having to mess with IPC messages.
main.js
mainWindow = new BrowserWindow({
webPreferences: {
preload: 'preload.js'
}
})
preload.js:
global.appRoot = window.appRoot = __dirname
index.html:
<script>
const { join } = require('path')
require(join(appRoot, 'rendererApp'))
</script>
Was having a similar issue. Try serving renderer.js over HTTP in your index.html like so,
<script src="/renderer.js"></script>
</body>
Then, as per the docs, load your module in using the adding remote after the require in your renderer.js file.
var spellCheck = require('electron-spell-check-provider').remote;
Related
I have a project by Three.js.
Like below pic, i have an index.html that uses js codes from scripts.js (in sub-Directory of js).
also, this scripts.js , uses three and OrbitControls libs of package of three.js.
PROBLEM:
after running my project, browser, shows HTML and CSS fine, but it do not works by javascript and gives this error:
i can't find any solution, after half a Day searching & manipulating!
can any one help please?
1)project structure:
root
|------server.js
|------/public
| |---index.html
| |---/js/scripts.js
| |---/css/index.css
2)root/public/index.html:
3)root/public/js/scripts.js:
4)root/server.js:
const express = require("express");
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, '/public')));
app.get('/',function(req,res) {
res.sendFile("public/index.html")
});
app.listen(3000, () => {console.log("listening on port 3000");});
Multiple things going on here. First, require() is nodejs ONLY, is not present in the browser. You are trying to load and run js/scripts.js in the browser and thus cannot use require() in that script.
Separately, when you use type="module" in a script tag, that means the module is an ESM module which can use import to load other modules, but import needs to specify a URL that your express server will handle and serve the right file with.
I'm also guessing that you will have a problem loading the script files because they need to be served by express.static() in your server and need to have the appropriate URL paths in your web page so that express.static() will work. You don't show the server-side file structure for all those scripts so it's hard for us to know exactly what the URLs should be.
And, in the future, please don't ever post screen shots of code. That makes it a lot harder for us to use your code in tests or in answers (because we have to retype it all from scratch) and it can't be searched, is harder to read on mobile, etc... Don't put code in images.
Is it possible to host web page with angular.min.js functionality using nodes http module?
I'm making a really simple web project that is going to fetch some data and I decided to use angular.js to display data no the page. I tried to read index.html using fs module and sent it as response to the localhost. It seems that angular.min.js, that was included in the pages head section did not load as it would when I run the page in the browser from the file explorer.
angular is a web application, so, please serve the angular using your node.js server and load the app in the web browser.
add a listener of get then send all files that index.html need, it is done.
or use app.use(express.static('public')); which public is your 'public' folder, put all file in dist to serve as a static content.
I use the first option every time but it is trick but functional.
sample code is:
const express = require('express');
const router = express.Router();
const path = require('path');
router.get('/:id',(req,res)=>{res.sendFile(path.join('/path/to your/file/'+req.params.id));});
router.get('/',(req,res)=> res.sendFile(path.join('/path/to/your/file/index.html'));});
module.exports = router;
I have a expressJs setup which looks like this:
// Imports...
const app: express.Application = express();
const port: number = 3001;
const listener = new StatementListenerAPI();
app.use('/listen', listener.getRouter());
app.use('/welcome', router);
if (fs.existsSync('./client')) {
// Running in prod environment with pre built client directory. Serve this.
app.use(express.static('./client'));
}
app.listen(port);
So I have some routers connected to the express app, and at the bottom I declare that the directory client should be served statically. This directory contains an index.html as well as lots of JS, CSS and PNG files. However, no matter which URL I try to access from the express server, it always shows the code of the index.html within the statically served directory. The references to the JS and CSS files used inside the index.html also just return the code of the index.html.
I am using ExpressJS 4.16.3
What am I doing wrong?
Edit: So technically it works if using __dirname + '/client' instead of ./client. What I am now getting is that, when making GET requests from e.g. Postman (therefore "hand-crafting" the HTTP requests), I am always getting the correct results. If I call the resources from within my web browser, it still always shows the website (resolves the index.html). However, now all resources like JS and CSS scripts are being resolved properly, so apperantly Chrome resolves those dependencies properly, I am just wondering why I am still getting the contents of index.html as result when requesting some of the assets or some of the express endpoints via Chrome. API calls via code are working fine, so its only why manual chrome requests show this weird behaviour, at this point I am only asking out of curiosity.
Answer to your original question:
The path supplied to express.static should be relative to the directory from where you launch your node process or an absolute path. To be safe construct an absolute path (ie from the current directory or file). For example:
app.use(express.static(__dirname + '/client'));
Regarding your followup question:
I assume this is because Chrome uses heavy caching and it thinks this folder should return the html file. You can try and reset all caches in Chrome, or just for the page.
I've managed to properly use webpack dev server alongside with a node server (express), using the plugin section inside webpack's config.
It all works fine but now I'm trying to go isomorphic and use client-side components inside the express application.
So far the only problem I'm encountering is that without webpack 'parsing' my server-side code I get to a situation where I require components but the paths are not solved
I.E.
Inside a component
'use strict';
import React from 'react';
import { RouteHandler, Link } from 'react-router';
import Header from 'components/header/main'; // <-- This line causes the error because webpack is not working when parsing this JSX server-side
export default React.createClass({
displayName: 'App',
render() {
return ( // ... More code
Shall I configure webpack in another way or do I have to change all the imports to be valid server-side?
the codebase is here in case you want to see the actual state https://github.com/vshjxyz/es6-react-flux-node-quickstart
In order to be able to require components in a way such as require('components/Header.js'); and avoid using long relative paths such as require('../../../../../../Header.js'); you can add this code to your node app before any require() calls:
process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();
However, since this relies on a private Node.js core method, this is
also a hack that might stop working on the previous or next version of
node.
Other possible solutions to this problem can be found at https://gist.github.com/branneman/8048520
I see 2 options:
Compile client code with webpack as well. If client's entry
point is in the same dir as server's - it should work with your
present code. This looks natural to me.
Use relative paths i.e.
import Header from './components/header/main'
Other than a nice way to require all files in a directory (node.js require all files in a folder?), what is index.js used for mainly?
When you pass a folder to Node's require(), it will check for a package.json for an endpoint. If that isn't defined, it checks for index.js, and finally index.node (a c++ extension format). So the index.js is most likely the entry point for requiring a module.
See the official Docs here: http://nodejs.org/api/modules.html#modules_folders_as_modules.
Also, you ask how to require all the files in a directory. Usually, you require a directory with an index.js that exposes some encapsulated interface to those files; the way to do this will be different for ever module. But suppose you wanted to include a folder's contents when you include the folder (note, this is not a best practice and comes up less often than you would think). Then, you could use an index.js that loads all the files in the directory synchronously (setting exports asynchronously is usually asking for terrible bugs) and attaches them to module.exports like so:
var path = require('path'),
dir = require('fs').readdirSync(__dirname + path.sep);
dir.forEach(function(filename){
if(path.extname(filename) === '.js' && filename !== 'index.js'){
var exportAsName = path.basename(filename);
module.exports[exportAsName] = require( path.join( __dirname, filename) );
}
});
I hardly ever see people wanting to use that pattern though - most of the time you want your index.js to go something like
var part1 = require('./something-in-the-directory'),
part2 = require('./something-else');
....
module.exports = myCoolInterfaceThatUsesPart1AndPart2UnderTheHood;
Typically in other languages the web server looks for certain files to load first when visiting a directory like / in priority, traditionally this is either: index or default. In php it would be index.php or just plain HTML it would be index.html
In Node.js, Node itself is the web server so you don't need to name anything index.js but it's easier for people to understand which file to run first.
index.js typically handles your app startup, routing and other functions of your application and does require other modules to add functionality. If you're running a website or web app it would also handle become a basic HTTP web server replacing the role of something more traditional like Apache.
Here is a good article explaining how Node.js looks for required module https://medium.freecodecamp.org/requiring-modules-in-node-js-everything-you-need-to-know-e7fbd119be8, with folder and index.js file
Modules don’t have to be files. We can also create a find-me folder
under node_modules and place an index.js file in there. The same
require('find-me') line will use that folder’s index.js file:
~/learn-node $ mkdir -p node_modules/find-me
~/learn-node $ echo "console.log('Found again.');" > node_modules/find-me/index.js
~/learn-node $ node
> require('find-me');
Found again.
{}
>
Late to the party but the answer is simply to allow a developer to specify the public api of the folder!
When you have a bunch of JavaScript files in a folder, only a small subset of the functions and values exported from these files should exportable outside of the folder. These carefully selected functions are the public apis of the folder and should be explicitly exported (or re-exported) from the index.js file. Thus, it serves an architectural purpose.