node.js - Electron 应用程序无法解析任何添加到 webpack 外部的节点模块
问题描述
我正在尝试使用 Vue.js 构建一个 Electron 应用程序。我正在使用 webpack-dev-server 在开发模式下运行电子应用程序。
在 webpack 配置中,我将所有 node_modules 添加到 externals 数组中,因为我不希望将它们捆绑在一起。
webpack 开发服务器成功启动,没有任何错误,应用程序也按预期启动,但我在控制台中收到以下错误。
Uncaught Error: Cannot find module 'frappejs'
.
注意:这不是唯一无法解析的模块。我添加到 webpack 外部数组的所有模块都无法解析。
如果我不将它们添加到 externals 数组中,则会检测到 node_modules 并且上述错误消失。
我注意到的另一件事是,
当我明确指向 node_modules 目录时,如果在这种情况下替换
const frappe = require('frappejs');
为错误也会消失。
const frappe = require('../../node_modules/frappejs');
这种行为的原因可能是什么?
配置.js
const webpack = require('webpack');
// plugins
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsWebpackPlugin = require('case-sensitive-paths-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { getAppConfig, resolveAppDir } = require('./utils');
const appDependencies = require(resolveAppDir('./package.json')).dependencies;
const frappeDependencies = require(resolveAppDir('./node_modules/frappejs/package.json')).dependencies;
// const frappeDependencies = require('../package.json').dependencies;
let getConfig, getElectronMainConfig;
function makeConfig() {
const isProduction = process.env.NODE_ENV === 'production';
process.env.ELECTRON = 'true';
const isElectron = process.env.ELECTRON === 'true';
const isMonoRepo = process.env.MONO_REPO === 'true';
const whiteListedModules = ['vue'];
const allDependencies = Object.assign(frappeDependencies, appDependencies);
const externals = Object.keys(allDependencies).filter(d => !whiteListedModules.includes(d));
getConfig = function getConfig() {
const appConfig = getAppConfig();
const config = {
mode: isProduction ? 'production' : 'development',
context: resolveAppDir(),
entry: isElectron ? appConfig.electron.entry : appConfig.dev.entry,
externals: isElectron ? externals : undefined,
target: isElectron ? 'electron-renderer' : 'web',
output: {
path: isElectron ? resolveAppDir('./dist/electron') : resolveAppDir('./dist'),
filename: '[name].js',
// publicPath: appConfig.dev.assetsPublicPath,
libraryTarget: isElectron ? 'commonjs2' : undefined
},
devtool: !isProduction ? 'cheap-module-eval-source-map' : '',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
},
{
test: /\.node$/,
use: 'node-loader'
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
},
resolve: {
extensions: ['.js', '.vue', '.json', '.css', '.node'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'deepmerge$': 'deepmerge/dist/umd.js',
'@': appConfig.dev.srcDir ? resolveAppDir(appConfig.dev.srcDir) : null
}
},
plugins: [
new webpack.DefinePlugin(Object.assign({
'process.env': appConfig.dev.env,
'process.env.NODE_ENV': isProduction ? '"production"' : '"development"',
'process.env.ELECTRON': JSON.stringify(process.env.ELECTRON)
}, !isProduction ? {
'__static': `"${resolveAppDir(appConfig.staticPath).replace(/\\/g, '\\\\')}"`
} : {})),
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: resolveAppDir(appConfig.dev.entryHtml),
nodeModules: !isProduction
? isMonoRepo ? resolveAppDir('../../node_modules') : resolveAppDir('./node_modules')
: false
}),
new CaseSensitivePathsWebpackPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: [`FrappeJS server started at http://${appConfig.dev.devServerHost}:${appConfig.dev.devServerPort}`],
},
}),
new webpack.ProgressPlugin(),
isProduction ? new CopyWebpackPlugin([
{
from: resolveAppDir(appConfig.staticPath),
to: resolveAppDir('./dist/electron/static'),
ignore: ['.*']
}
]) : null,
// isProduction ? new BabiliWebpackPlugin() : null,
// isProduction ? new webpack.LoaderOptionsPlugin({ minimize: true }) : null,
].filter(Boolean),
optimization: {
noEmitOnErrors: false
},
devServer: {
// contentBase: './dist', // dist path is directly configured in express
hot: true,
quiet: true
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// process is injected via DefinePlugin, although some 3rd party
// libraries may require a mock to work properly (#934)
process: 'mock',
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
return config;
}
getElectronMainConfig = function getElectronMainConfig() {
const appConfig = getAppConfig();
return {
entry: {
main: resolveAppDir(appConfig.electron.paths.main)
},
externals: externals,
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.node$/,
use: 'node-loader'
}
]
},
node: {
__dirname: !isProduction,
__filename: !isProduction
},
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: resolveAppDir('./dist/electron')
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
// isProduction && new BabiliWebpackPlugin(),
isProduction && new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
})
].filter(Boolean),
resolve: {
extensions: ['.js', '.json', '.node']
},
target: 'electron-main'
}
}
}
makeConfig();
module.exports = {
getConfig,
getElectronMainConfig
};
注意:resolveAppDir 函数返回与传递的参数连接的 cwd 路径。
解决方案
推荐阅读
- docker - 在构建和构建 docker 容器时,如何启动 cron 和 supervisor 等服务?
- python - Python 窗口打开和关闭
- ios - 检测不在 UISubView 上的点击手势
- python - 如何使用 Selenium 和 Python 单击 p-dropdown 标记内的元素
- python - 是否可以将 numpy int64 数组转换为 int 类型
- sas - 如何在SAS中将一列拆分为多行
- java - 如何在 updateUiChanged() 事件之前捕获 Java windowIconified() 和 windowIDeconified()?
- datatable - ado.net 中的 ResultSet TYPE_SCROLL_SENSITIVE 相等功能
- angular - 使用 Ng-select 显示搜索结果的延迟
- node.js - 在 Mongoose 保存后挂钩中捕获并忽略/抑制错误