如何pipe理Webpack / Electron应用程序的configuration?

我正在使用Webpack 2和Electron在Mac上构buildnodejs应用程序。

在我的项目在根目录中我有目录“数据”,我把configuration存储在一个JSON像data / configurations / files.json(实践中有不同的文件与dynamic名称)

虽然当我打电话时, fs.readdirSync(remote.app.getAppPath());fs.readdirSync(remote.app.getAppPath()); 获取根文件我只得到这些打包: [ "default_app.js", "icon.png", "index.html", "main.js", "package.json", "renderer.js" ]

path.join(remote.app.getAppPath(), 'data/tests/groups.json'); 用FS ReadSync调用会导致问题Error: ENOENT, data/tests/groups.json not found in /Users/myuser/myproject/node_modules/electron/dist/Electron.‌​app/Contents/Resourc‌​es/default_app.asar 。 所以看起来,整个数据文件夹是不是由networking包装拾起。

Webpack的configuration是使用json-loader ,我没有发现任何关于包含特定文件或jsons的文档。 或者我必须以不同的方式引用json文件,因为它们可能在main.js中打包。

Electron / Webpackpipe理JSONconfiguration文件的最佳做法是什么? 当我在做项目的时候,我做错了什么?

我的项目是基于https://github.com/SimulatedGREG/electron-vue使用webpack / electron / vue

Webpack的误解

有一点需要了解的是, webpack不会捆绑通过fs或其他需要文件path的模块所需的文件。 这些types的资产通常被标记为静态资产 ,因为它们不以任何方式捆绑在一起。 webpack将只捆绑require d或import文件(ES6)。 此外,根据您的webpackconfiguration,您的项目根目录可能并不总是与生产版本中的输出相匹配。

基于电子vue文档的项目结构/文件树 ,您将发现只有webpack包和static/目录在生产版本中可用。 electron-vue也有一个方便的__static全局variables,可以在开发和生产环境中为static/文件夹提供一个path。 你可以使用这个variables类似于用__dirnamepath.join来访问你的JSON文件,或者真正的任何文件。

静态资产解决scheme

看来电子vue样板文件的当前版本已经为您解决了这个问题,但是我将会描述如何使用webpack设置,因为它不仅适用于JSON文件,也适用于任何webpack + electron设置。 以下解决scheme假定您的webpack构build输出到一个单独的文件夹,在这种情况下,我们将使用dist/ ,假定您的webpackconfiguration位于项目的根目录中,并假定process.env.NODE_ENV在开发process.env.NODE_ENV中设置为开发。

static/目录

在开发过程中,我们需要一个地方来存储我们的静态资产,所以让我们把它们放在一个名为static/的目录中。 在这里,我们可以放置诸如JSON之类的文件,我们知道我们需要用fs或其他需要完整文件path的模块来读取这些文件。

现在我们需要在生产版本中提供static/资产目录。

但是webpack根本没有处理这个文件夹,我们能做什么?

我们来使用简单的copy-webpack-plugin 。 在我们的webpackconfiguration文件中,我们可以在构build生产时添加此插件,并将其configuration为将static/文件夹复制到我们的dist/文件夹中。

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

好,所以资产正在生产中,但是如何在开发和生产中获得这个文件夹的path?

创build一个全局__staticvariables

使这个__staticvariables有什么意义?

  1. 使用__dirnamewebpack + electron设置中不可靠。 在开发过程中, __dirname 可以参考src/ files中存在的目录。 在生产中,由于webpack我们的src/文件捆绑到一个脚本中,您形成的static/path不再存在。 而且,你放在src/里面那些require d或者imported的文件也不会把它放到你的生产版本中。

  2. 在处理与开发和生产相关的项目结构差异时,试图获得static/pathstatic/将在开发过程中非常烦人,必须始终检查您的process.env.NODE_ENV

所以让我们通过创build一个真实的来源来简化这一点。

使用webpack.DefinePlugin我们可以在开发中设置我们的__staticvariables来产生一个指向<projectRoot>/static/的path。 根据您是否拥有多个webpackconfiguration,您可以将其应用于main rendererrenderer进程configuration。

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

在生产中,我们需要在代码中手动设置__staticvariables。 这是我们可以做的…

index.htmlrenderer进程)

 <!-- 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.jsmain进程)

 // 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 

现在开始使用你的__staticvariables

比方说,我们有一个简单的JSON文件,我们需要用fs来读取,这里是我们现在可以完成的…

static/someFile.json

 {"foo":"bar"} 

someScript.jsrenderermain进程)

 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 } 

结论

webpack是将资源捆绑在一起, require d或import到一个很好的捆绑。 使用fs或其他需要文件path的模块引用的资源被视为静态资产 ,而webpack不直接处理这些资源。 使用copy-webpack-pluginwebpack.DefinePlugin我们可以设置一个可靠的__staticvariables,在开发和生产过程中产生一个到static/资产目录的path。

最后,我个人还没有看到任何其他webpack + electron样本处理这种情况,因为它不是一个很常见的情况,但我认为我们都可以同意静态资产目录中有一个真实的来源是一个奇妙的方法缓解开发商的疲劳。

我认为,混淆(如果有的话)可能来自webpack不仅“包装”,embedded,事物,代码等,而且还包含插件的内容。

html插件是一个很好的例子,因为它只是在构build时生成一个html文件。

这和configuration文件的问题有什么关系?这取决于你如何“需要”“configuration”文件,你正在使用什么插件来处理这些内容。

你可以embedded它,或者简单地加载它作为文本,从文件系统或http,否则…

在configuration文件的情况下,我想你想在运行时parsing它,
否则它只是硬编码的价值观,也许你可以更好地简单地在源代码中input它作为简单的对象。

而且在这种情况下,我认为webpack对运行时的需求几乎没有什么影响,因为在以后的使用中没有什么可以预先打包的,

所以我可能会相反或“需要”它,我会从文件系统读取,如下所示:

 // 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 

电子将从文件系统中读取,或者如果使用Electron.require将从asar | fileSystem中读取(如果我没有记错的话,我可能是错的),

Webpack的devise理念围绕着非常简单而强大的概念:

转换和捆绑您的应用程序实际使用的所有内容。

为了实现这一点,webpack引入了一个强大的依赖关系图的概念,它能够通过所谓的装载器来pipe理几乎任何types的依赖关系(不仅仅是* .js模块)。

加载器的目的是转换你的依赖关系,使得import smth from 'your_dependency'语句有意义。 例如, json-loader在加载* .json文件期间调用JSON.parse(...)并返回configuration对象。 因此,为了利用webpack依赖parsing系统来pipe理JSON,从安装json-loader

 $ npm install --save-dev json-loader 

然后按以下方式修改你的webpack.config.js

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

在这一点上,webpack应该能够通过它们的绝对path来parsing你的JSON依赖,所以下面应该可以工作(我假设你有一个你的根上下文目录的子目录config ,包含文件sample.json ):

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

但是导入物理path不会导致优雅,健壮和可维护的代码(例如考虑可testing性),因此向webpack.config.js添加别名以webpack.config.js物理.config/文件夹从您的import报表

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

那么你将能够像这样导入你的JSONconfiguration:

 import sampleCfg from 'cfg/sample.json' 

最后,如果您使用SimulatedGREG/electron-vue电子项目模板(如您在文章中提到的那样),那么您有三个webpackconfiguration文件:

  • .electron-vue/webpack.web.config.js – 使用这个configuration文件,如果你使用这个模板只是为了普通的web开发(即不build立本地电子项目)。

  • .electron-vue/webpack.main.config.js – 使用此文件configuration将运行在Electron主进程内的webpack模块;

  • .electron-vue/webpack.renderer.config.js – 将此文件用于Electron的渲染器进程。

您可以在官方的Electron文档中find更多关于main和renderer进程的信息 。