How can I add JSON or TOML files in an Electron app for deployment? The following code works in development environment, but does not after packaging by electron-packager.
var presets = toml.parse(fs.readFileSync('presets.toml','utf8'));
According to the guide that took me way too long to find, the Electron team patched the fs module to provide a "virtual file system" under the root (/).
That means your file is accessible at fs.readFileSync('/presets.toml'); (notice the forward slash).
I went crazy till I found this one.
The problem is not adding it because it's already added.
Problem is finding base path after packaging.
So here it is:
const { app } = window.require('electron').remote;;
console.log(app.getAppPath());
Also, as you can see, if you're using React you need to use window.require instead of regular require (it throws nasty error otherwise).
Found about this here:
https://github.com/electron/electron/issues/3204#issuecomment-151000897
Related
I’m using Electron Builder to compile my Electron app to an .AppImage file, and I’m using the fs module to write to an .json file, but it’s not working in the appimage format (it’s working fine when I have the normal version not made with Electron Builder). I can still read from the file.
The code (preload):
setSettings: (value) => {fs.writeFileSync(path.join(__dirname, "settings.json"), JSON.stringify(value), "utf8")}
The code (on the website):
api.setSettings(settings);
The project: https://github.com/Nils75owo/crazyshit
That's not a problem with AppImage or Electron Builder but with the way you're packaging your app. Since you didn't post your package.json*, I can only guess what's wrong, but probably you haven't changed Electron Builder's default behaviour regarding packing your application.
By default, Electron Builder compiles your application, including all resources, into a single archive file in the ASAR format (think of it like the TAR format). Electron includes a patched version of the fs module to be able to read from the ASAR file, but writing to it is obviously not supported.
You have two options to mitigate this problem: Either you store your settings somewhere in the user's directory (which is the way I'd go, see below) or you refrain from packing your application to an ASAR file, but that will leave all your JavaScript code outside the executable in a simple folder. (Note that ASAR is not capable of keeping your code confidential, because there are applications which can extract such archives, but it makes it at least a little harder for attackers or curious eyes to get a copy of your code.)
To disable packing to ASAR, simply tell Electron Builder that you don't want it to compile an archive. Thus, in your package.json, include the following:
{
// ... other options
"build": {
// ... other build options
"asar": false
}
}
However, as I mentioned above, it's probably wiser to store settings in a common place where advanced users can actually find (and probably edit, mostly for troubleshooting) them. On Linux, one such folder would be ~/.config, where you could create a subdirectory for your application.
To get the specific application data path on a cross-platform basis, you can query Electron's app module from within the main process. You can do so like this:
const { app } = require ("electron"),
path = require ("path");
var configPath;
try {
configPath = path.join (app.getPath ("appData"), "your-app-name");
} catch (error) {
console.error (error);
app.quit ();
}
If you however have correctly set your application's name (by using app.setName ("...");), you can instead simply use app.getPath ("userData"); and omit the path joining. Take a look at the documentation!
For my Electron Applications, I typically choose to store settings in a common hidden directory (one example for a name could be the brand under which you plan to market the application) in the user's home directory and I then have separate directories for each application. But how you organise this is up to you completely.
* For the future, please refrain from directing us to a GitHub repository and instead include all information (and code is information too) needed to replicate/understand your problem in your question. That'd save us a lot of time and could potentially get you answers faster. Thanks!
I am building a React application which needs to display images dynamically which are stored, by the thousands, on a server-side file system. All of my attempts to successfully implement this have failed, including many which were taken from responses to similar questions.
Some details:
I used create-react-app to initialize my application. I am running in development mode (have not run npm-build). I'm using Express.js (Node.js) as a web-server, which I interact with through a proxy (only '/api' http requests use the proxy). My js code which attempts to 'require' the images is in the 'src' folder. The images are located in an 'images' folder in the default 'public' folder.
I thought I had found the solution when reading this page from create-react-app, as it states to use the public folder when 'You have thousands of images and need to dynamically reference their paths'. The page further instructs to use '%PUBLIC_URL%' or 'process.env.PUBLIC_URL' to access the 'public' folder. When using either of these I receive an 'Error: Cannot find module' message. Upon checking I notice that 'process.env.PUBLIC_URL' contains an empty string, and quickly notice that PUBLIC_URL is ignored in development mode.
I find this to be tremendously confusing, given that the 'Using the Public Folder' page is apparently describing the development phase of production, and yet it advises the use of something which is meaningless during development. Adding to my confusion, it appears as if the contents of that page resolved the issue for nearly all of those who have encountered a similar requirement in the past (example: 1, example: 2; both fail for me). Likewise, all attempts to to construct relative paths to the 'public' folder from the 'src' folder have yielded error messages. Failed code example:
let img = process.env.PUBLIC_URL + '/images/Team.jpg';
<img src={require(`${img}`)} alt="X" />
Error: Cannot find module '/images/Team.jpg'
I never imagined showing images in React would be so difficult. Any help is truly very much appreciated.
I think you are correct, you just don't need the require, return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />; as you can see their docs
If you open in your browser http://localhost:PORT/images/Team.jpg that should open.
That's the reason process.env.PUBLIC_URL is empty in development, because they resolve everything inside this folder directly.
This is somewhat related to an issue I'm having with CF on IBM Cloud here. My question after playing around with the folder structures is how exactly is CF building the app when it comes to relative paths?
For example, if i have the following folder structure
when I add <script type = 'text/javascript' src = '../index.js'></script> to the index.html file, I get GET https://simple-toolchain-20190320022356947.mybluemix.net/index.js net::ERR_ABORTED 404. This error does not happen when I move index.js into the public folder and change <script type = 'text/javascript' src = 'index.js'></script>.
The problem I have then is that when I try to require() any modules when the index.js file is in a sub-directory, it returns a Require is not defined error indicating that it is not getting the module from the node_modules cache which CF is suppose to build. Requiring any files in the same sub-directory also throws the same error. This does not seem to be a problem when the require() is used in the default app.js as the application loads without any errors.
I'm relatively new to the IBM Cloud Foundry tool but I'm following the same structure as when I pushed apps via Cloud9 IDE and didn't have any such issues there. I feel I might be missing something ridiculously simple like configuration of endpoint or package.json. However, I've been searching around for days and can't seem to find a solution.
Appreciate if you have any pointers. Thanks!
Due to my lack of understanding, I was trying to use require() on the client side hence the errors. Going to figure out how to use Browserify now. ;)
Current code in /config/index.js
const options = (require('js-yaml')).safeLoad(
(require('fs')).readFileSync(`./config/default-config.yaml`, "utf8"));
module.exports = options;
Works fine. Until I publish and use it in my other project. Then it's unable to find the file (naturally) as ./config/default-config.yaml doesn't exist in that project.
The only option I can think of involves checking to see if the file exists at that path, then trying to load it from node_modules/#company/alpha-gamma/config/default-config.yaml. This seems really hacky.
The config object is large, 200+ keys. I don't think it belongs in the code.
What's the best solution for loading a file that exists inside your module? I need to be able to load it for unit tests before publishing and load it at runtime when the library is required by another module.
Maybe the best alternative is to use json since I can then use the require module to load it in, instead of fs.
While I originally suggested utilizing __dirname as a valid option, I was wrong. Calling process.cwd() to fetch the application root and building the path off of that is the best approach.
As documented here:
Proper way to reference files relative to application root in Node.JS
I'm building a web application in Node.js, and I'm implementing my API routes in separate modules. In one of my routes I'm doing some file manipulation and I need to know the base app path. If I use __dirname, it gives me the directory that houses my module of course.
I'm currently using this to get the base application path (given that I know the relative path to the module from base path):
path.join(__dirname, "../../", myfilename)
Is there a better way than using ../../? I'm running Node.js under Windows, so there isn't any process.env.PWD, and I don't want to be platform-specific anyway.
The approach of using __dirname is the most reliable one. It will always give you correct directory. You do not have to worry about ../../ in Windows environment as path.join() will take care of that.
There is an alternative solution though. You can use process.cwd() which returns the current working directory of the process. That command works fine if you execute your Node.js application from the base application directory. However, if you execute your Node.js application from different directory, say, its parent directory (e.g., node yourapp\index.js) then the __dirname mechanism will work much better.
You can define a global variable like in your app.js file:
global.__basedir = __dirname;
Then you can use this global variable anywhere. Like this:
var base_path = __basedir
You can use path.resolve() without arguments to get the working directory which is usually the base application path. If the argument is a relative path then it's assumed to be relative to the current working directory, so you can write
require(path.resolve(myfilename));
to require your module at the application root.