How to manage configuration for Webpack / Electron application?

I use Webpack 2 and Electron to build a nodejs application on a Mac.

In my project, in the root, I have directory data where I store the configuration in json as data / configurations / files.json (in practice there are different files with dynamic names)

After webpackaing, although when I call: fs.readdirSync(remote.app.getAppPath()); to get the files in the root, I get only these packages: [ "default_app.js", "icon.png", "index.html", "main.js", "package.json", "renderer.js" ]

path.join(remote.app.getAppPath(), 'data/tests/groups.json'); called with FS ReadSync leads to Error: ENOENT, data/tests/groups.json not found in /Users/myuser/myproject/node_modules/electron/dist/Electron.‌​app/Contents/Resourc‌​es/default_app.asar . Thus, it seems that the entire data folder is not loading the web packet.

The Webpack configuration uses json-loader , and I did not find any documentation that mentioned anything special about including specific files or jsons. Or do I need to reference json files in my code in different ways, as they can be packaged in main.js.

What is the best practice for Electron / Webpack to manage JSON configuration files? Am I doing something wrong when loading a project web?

My project is based on https://github.com/SimulatedGREG/electron-vue using webpack / electronic / vue

+7
javascript webpack electron
source share
3 answers

Misconception Webpack

One thing that understands in advance is that webpack does not bundle the files needed through fs or other modules that request a file path. These types of assets are usually referred to as Static assets , as they are not related in any way. webpack will only link require d or import ed (ES6) files. Also, depending on your webpack configuration, your project root may not always match what is displayed in your production builds.

Based on the documentation on electronic vue Project structure / File tree , you will find that only webpack packages and the static/ directory are available in production assemblies. electron-vue also has a convenient global __static variable, which can provide a path to this static/ folder during both development and production. You can use this variable, similar to how __dirname and path.join access your JSON files or indeed any files.

Static Asset Solution

It seems that the current version of electron-vue template has already resolved this for you, but I will tell you how it is with webpack , since it can be applied not only to JSON files, but also how it can be applied to any installation of webpack + electron . The following solution assumes that you are creating webpack outputs for a separate folder, in this case we will use dist/ , suppose your webpack configuration is in the project root directory and assumes that process.env.NODE_ENV set to development during development.

static/ directory static/

During development, we need a place to store our static assets, so put them in a directory called static/ . Here we can put files, such as JSON, that we know that we will need to read using fs or another module, which requires the full path to the file.

Now we need to make this static/ resource directory available in production assemblies.

But webpack does not handle this folder at all, what can we do?

Use a simple copy-webpack-plugin . In our webpack configuration file webpack we can add this plugin when creating for production and configure it to copy the static/ folder to our dist/ folder.

 new CopyWebpackPlugin([ { from: path.join(__dirname, '/static'), to: path.join(__dirname, '/dist/static'), ignore: ['.*'] } ]) 

Well, so the assets are in production, but how do I get the path to this folder in both development and production?

Creating the __static global variable

What is the point of making this __static variable?

  • Using __dirname not reliable in webpack + electron settings. At design time, __dirname may refer to the directory that exists in your src/ files. During production, since webpack our src/ files into one script, this path that you created for static/ no longer exists. Also, those files that you put inside src/ that were not require d or import ed never get into your production assembly.

  • When handling differences in project structure from development to production, trying to get a static/ path will be very annoying during development to always check your process.env.NODE_ENV .

So simplify this by creating one source of truth.

Using webpack.DefinePlugin , we can only set our __static variable in development to get a path pointing to <projectRoot>/static/ . If you have multiple webpack configurations, you can use this to configure the main and renderer process.

 new webpack.DefinePlugin({ '__static': `"${path.join(__dirname, '/static').replace(/\\/g, '\\\\')}"` }) 

In the production process, we need to set the __static variable manually in our code. Here is what we can do ...

index.html ( renderer process)

 <!-- Set `__static` path to static files in production --> <script> if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') </script> <!-- import webpack bundle --> 

main.js ( main process)

 // Set `__static` path to static files in production if (process.env.NODE_ENV !== 'development') { global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') } // rest of application code below 

Now start using the __static variable

Let's say we have a simple JSON file that we must read with fs , here that we can execute now ...

static/someFile.json

 {"foo":"bar"} 

someScript.js ( renderer or main process)

 import fs from 'fs' import path from 'path' const someFile = fs.readFileSync(path.join(__static, '/someFile.json'), 'utf8') console.log(JSON.parse(someFile)) // => { foo: bar } 

Conclusion

webpack was made to webpack assets together that require d or import ed into one good package. Assets referenced by fs or other modules that need a file path are considered Static assets , and webpack does not directly process them. Using copy-webpack-plugin and webpack.DefinePlugin , we can configure the robust __static variable, which gives the path to our static/ resource directory in both development and production.

To finish, I personally have not seen any other webpack + electron templates handle this situation, since this is not a very common situation, but I think we can all agree that one source of truth is the Static Assets Directory is a great approach to mitigating developer fatigue.

+11
source share

I think that confusion (if any) may arise due to the fact that webpack not only “packs”, implements, things, code, etc., but also processes the content with its plugins.

The html plugin is a good example, as it simply generates an html file at build time.

And how does this relate to the problem with the configuration file ?, it’s good depending on how you “need” the “config” file, which plug-in you use to process this content.

You can embed it or just load it as text from a file system or http, otherwise ...

In the case of a configuration file, which I think you want it to parse at runtime,
otherwise, it simply attaches importance to hard coding; perhaps it may be easier for you to simply enter it into the source code as simple objects.

And again in this case, I think that webpack adds almost nothing to the needs of the runtime, since there is no need to pre-pack to read on subsequent use,

so I could instead “require” it, I will read it from the file system with something like:

 // read it parse it relative to appPath/cwd, const config = JSON.parse( fs.readfileSync( path.join( app.getAppPath(), "config.json" ), "utf-8" )) //note: look fs-extra, it does all that minus the app.path plus async 

and the electron will read it from the file system or if using Electron.require will read it from asar | fileSystem (in that order, if I remember correctly, I could be wrong)

+2
source share

Webpack's design philosophy is focused on a very simple but powerful concept:

Converting and combining everything that is really used by your application.

To achieve this, webpack is a powerful dependency graph concept that can manage almost any dependency (not just * .js modules) using so-called loaders.

The purpose of the loader is to transform your dependency in such a way as to make the import smth from 'your_dependency' meaningful. For example, json-loader calls JSON.parse(...) during the loading of a * .json file and returns a configuration object. Therefore, to use the webpack dependency resolution system to control JSON, start by installing json-loader :

 $ npm install --save-dev json-loader 

Then modify your webpack.config.js as follows:

 module.exports = { ... module: { rules: [ {test: /\.json$/, use: 'json-loader'} ] } ... }; 

At this point, the web package should be able to resolve your JSON dependencies in their absolute paths, so the following should work (I assume that you have a config subdirectory of your dir root directory containing the sample.json file):

 import sampleCfg from './config/sample.json'; 

But importing physical paths does not lead to elegant, reliable, and maintainable code (e.g. testing), so it is considered good practice to add aliases to your webpack.config.js to abstract your physical .config/ from your import statements

 module.exports = { ... resolve: { alias: { cfg: './config' } } ... } 

Then you can import the JSON configuration as follows:

 import sampleCfg from 'cfg/sample.json' 

Finally, if you use the SimulatedGREG/electron-vue Electron project template (as you mentioned in your post), then you have three webpack configuration files:

  • .electron-vue/webpack.web.config.js - use this configuration file if you use this template only for regular web development (i.e. not to create your own Electron projects);

  • .electron-vue/webpack.main.config.js - use this file to configure the webpack module that will work inside the main Electron process;

  • .electron-vue/webpack.renderer.config.js - use this file for the electron rendering process.

Further information on basic and visualization processes can be found in Electron's official documentation .

+1
source share

All Articles