I have a problem with webpack in a React + ts + electron based application.
Specifically, the application works in the 'dev' environment - the browser version opens and loads all styles and images.
However, after executing the command "npm run package" ("package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never"), the local application is built on the local electron platform, an exe file appears, it is installed and the application is launched, but it does not have loaded styles and images.
It seems to me that the problem is with the webpack configuration file. webpack.config.renderer.dev.dll.ts:
/**
* Builds the DLL for development electron renderer process
*/
import webpack from 'webpack';
import path from 'path';
import { merge } from 'webpack-merge';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import { dependencies } from '../../package.json';
import checkNodeEnv from '../scripts/check-node-env';
checkNodeEnv('development');
const dist = webpackPaths.dllPath;
const configuration: webpack.Configuration = {
context: webpackPaths.rootPath,
devtool: 'eval',
mode: 'development',
target: 'electron-renderer',
externals: ['fsevents', 'crypto-browserify'],
/*
* Use `module` from `webpack.config.renderer.dev.js`
*/
module: require('./webpack.config.renderer.dev').default.module,
entry: {
renderer: [
...Object.keys(dependencies || {}),
]
},
// entry: {
// renderer: [
// ...Object.keys(dependencies || {}),
// 'primeflex',
// 'primeicons',
// 'primereact',
// ].filter(key => key !== 'primeflex' && key !== 'primeicons' && key !== 'primereact')
// },
output: {
path: dist,
filename: '[name].dev.dll.js',
library: {
name: 'renderer',
type: 'var',
},
},
plugins: [
new webpack.DllPlugin({
path: path.join(dist, '[name].json'),
name: '[name]',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: webpackPaths.srcPath,
output: {
path: webpackPaths.dllPath,
},
},
}),
],
};
export default merge(baseConfig, configuration);
The webpack dev configuration file webpack.config.renderer.dev.ts:
import 'webpack-dev-server';
import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import chalk from 'chalk';
import { merge } from 'webpack-merge';
import { execSync, spawn } from 'child_process';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import checkNodeEnv from '../scripts/check-node-env';
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
// at the dev webpack config is not accidentally run in a production environment
if (process.env.NODE_ENV === 'production') {
checkNodeEnv('development');
}
const port = process.env.PORT || 1212;
const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json');
const skipDLLs =
module.parent?.filename.includes('webpack.config.renderer.dev.dll') ||
module.parent?.filename.includes('webpack.config.eslint');
/**
* Warn if the DLL is not built
*/
if (
!skipDLLs &&
!(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest))
) {
console.log(
chalk.black.bgYellow.bold(
'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"'
)
);
execSync('npm run postinstall');
}
const configuration: webpack.Configuration = {
devtool: 'inline-source-map',
mode: 'development',
target: ['web', 'electron-renderer'],
entry: [
`webpack-dev-server/client?http://localhost:${port}/dist`,
'webpack/hot/only-dev-server',
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
],
output: {
path: webpackPaths.distRendererPath,
publicPath: '/',
filename: 'renderer.dev.js',
library: {
type: 'umd',
},
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
// webpackImporter: false,
},
},
'sass-loader',
],
include: /\.module\.s?(c|a)ss$/,
},
{
test: /\.s?css$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /\.module\.s?(c|a)ss$/,
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
// Images
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
// SVG
{
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
'file-loader',
],
},
],
},
plugins: [
...(skipDLLs
? []
: [
new webpack.DllReferencePlugin({
context: webpackPaths.dllPath,
manifest: require(manifest),
sourceType: 'var',
}),
]),
new webpack.NoEmitOnErrorsPlugin(),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*
* By default, use 'development' as NODE_ENV. This can be overriden with
* 'staging', for example, by changing the ENV variables in the npm scripts
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
}),
new ReactRefreshWebpackPlugin(),
new HtmlWebpackPlugin({
filename: path.join('index.html'),
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
},
isBrowser: false,
env: process.env.NODE_ENV,
isDevelopment: process.env.NODE_ENV !== 'production',
nodeModules: webpackPaths.appNodeModulesPath,
}),
],
node: {
__dirname: false,
__filename: false,
},
devServer: {
port,
compress: true,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
static: {
publicPath: '/',
},
historyApiFallback: {
verbose: true,
},
setupMiddlewares(middlewares) {
console.log('Starting preload.js builder...');
const preloadProcess = spawn('npm', ['run', 'start:preload'], {
shell: true,
stdio: 'inherit',
})
.on('close', (code: number) => process.exit(code!))
.on('error', (spawnError) => console.error(spawnError));
console.log('Starting Main Process...');
let args = ['run', 'start:main'];
if (process.env.MAIN_ARGS) {
args = args.concat(
['--', ...process.env.MAIN_ARGS.matchAll(/"[^"]+"|[^\s"]+/g)].flat()
);
}
spawn('npm', args, {
shell: true,
stdio: 'inherit',
})
.on('close', (code: number) => {
preloadProcess.kill();
process.exit(code!);
})
.on('error', (spawnError) => console.error(spawnError));
return middlewares;
},
},
};
export default merge(baseConfig, configuration);
When I received the error message: module: require('./webpack.config.renderer.dev').default.module, error code: Cannot find name 'require'. Do you need to install type definitions for node? Try npm i --save-dev @types/node.ts(2580)
I installed type definitions for Node.js by running the command npm i --save-dev @types/node
in the project directory.
However, the error persisted, so I made sure that the tsconfig.json file in the project contained the section "compilerOptions": {"module": "commonjs"}
- which it did.
In the webpack.config.renderer.dev.dll.ts file, I added an import for the require module by adding import * as nodeRequire from 'require'; at the beginning. Then I used nodeRequire instead of require, but this did not help.