electron-builder not working for production due to path - reactjs

everyone
I created a React app in order to build an electron app. I'm trying to use electron-builder to create the installers. I'm working on Ubuntu trying to generate a .deb.
I didn't use create-react-app, I used a boilerplate I already had, but I don't know if this is the problem.
I can make it work as long as I edit the index.html the webpack generates in the build folder. I have to change the path to main.css and build.js from /main.css and /build.js to ./main.css and ./build.js.
I read that I have to use the "homepage" property in package.json, but it's not working, seems to be ignored.
My folder structure is like:
package.json
src/
config/
main_electron_file.js
build/ #generated by webpack when I run the 'build:prd' command
public/ #empty
package.json
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "./main_electron_file.js",
"scripts": {
"dev": "./node_modules/.bin/webpack-dev-server --config ./config/webpack.config.dev.js --mode development --open --hot",
"build:prd": "./node_modules/webpack/bin/webpack.js --mode production --config ./config/webpack.config.prd.js --env.NODE_ENV=production --progress",
"electron": "electron .",
"start": "npm run dev && npm run electron",
"start:dev": "ELECTRON_START_URL=http://localhost:3000 electron .",
"dist": "build"
},
"keywords": [],
"author": {
"name": "name",
"email": "email#mail.com"
},
"license": "ISC",
"dependencies": {
...
},
"devDependencies": {
...
},
"homepage": "./",
"build": {
"appId": "com.myself.myapp",
"linux": {
"target": [
"deb"
]
}
}
}
main_electron_file.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow() {
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, 'build/index.html'),
protocol: 'file:',
slashes: true
});
// Create the browser window.
mainWindow = new BrowserWindow({ width: 800, height: 600, resizeble: false });
mainWindow.setResizable(false);
// and load the index.html of the app.
// win.loadURL('http://localhost:3000');
mainWindow.loadURL(startUrl);
// Open the DevTools.
mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
By the way. I'm not building it. I'm running it pointing to the index.html in the dist, as I would do in production mode. So i'm running npm run build:prd and then npm run electron
ANy ideas how I could make this process automatic?

Please try adding this line in your index.html
<base href="./">
And your main.css and build.js directory should be set relative to your index.html in build folder

What worked for me was:
Add to webpack config:
output: {
publicPath: './',
...
}
This tells webpack to have every link between files it creates based at the same directory.
As suggested by carlokid, add to index.html:
< base href="./" />

Related

Nrwl/React - Upload source maps to sentry

I'm working on a React application inside my NX Workspace.
Now I want to add sentry to my project. I already have a deploy configuration in my project.json. But I'm struggling with adding the step to upload the source maps.
Here is my project.json
"deploy": {
"executor": "nx:run-commands",
"options": {
"parallel": false,
"commands": [
{
"command": "nx run my-app:build:{args.target}",
"forwardAllArgs": true
},
{
"command": "echo Run {args.target} deployment on {args.server}",
"forwardAllArgs": true
},
{
"command": "rsync -avz --progress --delete dist/apps/my-app/ {args.user}#{args.server}:{args.path}",
"forwardAllArgs": true
},
{
"command": "echo my-app deployed to {args.target}",
"forwardAllArgs": true
}
]
},
"configurations": {
"production": {
"args": "--target=production --user=user --server=myserver.com --path=path/to/app"
}
}
}
Is there any example of how to perform the upload of the source maps using a nx workspace? Or do I have to create a custom script that handles everything and put it into my project.json as the second command (after build, before deploy).
Also, I'm not sure how to handle the version number of my application as NX does not provide a way to define version numbers for each application inside the workspace.
You'll have to create a custom webpack config on the Nx project: https://nx.dev/recipes/other/customize-webpack
and then follow the instructions on how to setup it on Sentry using webpack:
https://docs.sentry.io/platforms/javascript/guides/react/sourcemaps/uploading/webpack/
Your custom webpack should look like something like this:
const {merge} = require('webpack-merge')
const SentryWebpackPlugin = require('#sentry/webpack-plugin')
const nrwlConfig = require('#nrwl/react/plugins/webpack.js')
module.exports = (config) => {
// merge config from #nrwl/react first
nrwlConfig(config)
return merge(config, {
devtool: 'source-map', // Source map generation must be turned on
plugins: [
new SentryWebpackPlugin({
org: 'orgId',
project: 'projectId',
// Specify the directory containing build artifacts
include: './build',
// Auth tokens can be obtained from https://sentry.io/settings/account/api/auth-tokens/
// and needs the `project:releases` and `org:read` scopes
authToken: process.env.NX_SENTRY_AUTH_TOKEN,
// Optionally uncomment the line below to override automatic release name detection
// release: process.env.RELEASE,
}),
],
})
}
Please notice that unfortunately this is not a final answer, because with this I can upload the artifact, but the source maps are still not working on Sentry and I don't know why yet - but maybe this can be helpful somehow to you.

React compiler end up with Unexpected token <

I am beginner in React and I am struggling with compiler error. Let me introduce my situation. I have two independent React applications:
App A - Big ERP
App B - "Plugin" to the App A
I supposed I will develop App B as an independent application. Then, I will install it to the App A (using npm install git#github.repo/...) once I finish development of the App B. I expected I will call components from App B within the App A source code. Everything went fine until I run the compilation. I am receiving:
SyntaxError: /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js: Unexpected token
In my /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js there is following code:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Error is ocuring at the position of <p>.
I call this functional component from App A (frontend/src/views/Connector/ConnectorNewEditView/index.js) like this
import ConnectorFormView from "connector_frontend/src/views/Connector/FormView";
const ConnectorNewEditView = () => {
return (<ConnectorFormView AppValues={appValues} secureFetch={secureFetch} />)
}
export default ConnectorNewEditView;
I tried to return just a plain text from the ConnectorFormView component like this:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
'Hello world'
)
}
export default ConnectorFormView;
and it was compiled successfully, but once I return a JSX from the ConnectorFormView component the compiler get crashed.
Can anyone explain the source of this error please?
I successfully figured out the source of this problem and also I found a solution. I expected I can reuse however React component implemented in JSX. I expected, the only requirement is to install it, resp. download it in JSX form to my project using NPM. It's FALSE.
According to my research, I can reuse React components compiled from JSX to ES only. It is achievable using Babel. Another very important requiremen, it should not by installed as React application as I installed it. It must be installed as a NPM package with clearly defined set of exported components.
I found this paper https://levelup.gitconnected.com/publish-react-components-as-an-npm-package-7a671a2fb7f and I followed it step by step and finally I achieved desired result.
I can very briefly mention steps which I performed:
Implemented my custom component (mentioned above)
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Added the component to /src/index.js file in order to export it for host App
import ConnectorFormView from './components/ConnectorFormView';
export { ConnectorFormView };
Installed Babel and all needed presets
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install -save #babel/polyfill
configured Babel - created file /babel.config.json with following content
{
"presets": [
[
"#babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
],
"#babel/preset-react"
]
}
Added new script to the package.json to compile React components to ES:
"build": "rm -rf dist && NODE_ENV=production babel src --out-dir dist --copy-files";
Executed npm run build to compile React components to ES. Compiled components are located in new dist folder.
Adjusted package.json that looks like this now
{
"name": "my_react_components",
"version": "0.1.0",
"private": true,
"description": "Some description",
"author": "Lukas",
"main": "dist/index.js",
"module": "dist/index.js",
"files": [ "dist", "README.md" ],
"dependencies": {
.
.
},
"scripts": {
"build": "rm -rf dist && NODE_ENV=production babel src--out-dir dist --copy-files",
.
.
.
},
"eslintConfig": {
"extends": "react-app"
},
"devDependencies": {
"#babel/cli": "^7.17.10",
"#babel/core": "^7.18.5",
"#babel/preset-env": "^7.18.2"
}
}
Pushed dist folder to the git.
Installed repository to the host project using NPM
npm install https://github.com/my_custom/react_component.git
Import and use the component from installed git repo
import ConnectorFormView from 'my_react_components';
function App() {
return (
<ConnectorFormView />
);
}
export default App;
Actually that's all. I very recommend to see the attached paper at the beginning of this answer because I maybe skipped very important info for you.

electron & react: No resource with given URL found, DevTools failed to load SourceMap

For production (mac dmg) builds of my electron app, I am unable to trigger location.reload(), connect to redux-dev-tools, and the sourcemap fails to load.
When the app is loaded, the console warns that it cannot load the sourcemap:
The index.html in the sources says the resource cannot be loaded:
Executing location.reload() causes the app to crash with a white screen and no console logs (this command works in electron dev builds).
My electron code is contained in electron/index.electron.js and the relevant snippets are:
const options = {
icon: join(__dirname, '../src/common/assets/app-icons/png/256x256.png'),
webPreferences: {
nodeIntegration: false,
preload: join(__dirname, "preload.js")
}
};
// ...
mainWindow = new BrowserWindow({
...options,
...windowOptions
});
// ...
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: "file://../build/index.html"
});
// ...
mainWindow.loadURL(startUrl);
The relevant package.json snippets:
"homepage": "./",
"scripts": {
"electron-build:mac": "rm -rf dist/ && yarn build && electron-builder -m",
},
"build": {
"appId": "appId",
"extends": null,
"files": [
"dist/**/*",
"build/**/*",
"node_modules/**/*",
"src/common/assets/**/*",
"public/*",
"electron/**/*"
],
"directories": {
"buildResources": "./src/common/assets"
}
},
"devDependencies": {
"electron": "^11.3.0",
"electron-builder": "^22.9.1"
The only thing I can confirm in dev is that running location.reload() successfully reloads the app.
Thanks :)
your url is not valid,
you should change this:
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: "file://../build/index.html"
});
to this
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: "file://${ __dirname}/build/index.html"
});

Building a React-Electron app using electron-builder, index.js loads inside pre tags

I have an app that I'm now trying to build to distribute for testing.
I'm using React and Electron with electron-builder to build the app itself. I'm not a web developer so I've been trying to keep things basic and just get something to work.
After about five hours I was finally able to get the app to build somewhat properly and launch, but when it loads index.js (the first page in the app) it displays the source for index.js instead of rendering the content. In the devtools everything is inside a pre tag.
I've already looked at this thread and tried that but it didn't change anything, and I'm not using service workers as far as I can tell.
What the actual Electron window displays after launching with the devtools alongside.
Here's the createWindow function from main.js.
I've tried doing all kinds of things to the pathname with no effect.
function createWindow() {
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.js'),
protocol: 'file:',
slashes: true,
});
mainWindow = new BrowserWindow({
width: 800, height: 600, title: "Electron App", webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadURL(startUrl);
mainWindow.on('closed', function () {
mainWindow = null;
});
}
Here are my scripts from package.json
"scripts": {
"start": "nf start -p 3000",
"start-electron": "set ELECTRON_START_URL=http://localhost:3000 && electron .",
"react-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build-electron": "npm run build && electron-builder build --win"
}
Here's the build part too. To be honest, I don't really understand what this is or does but after a few hours of trial and error this is what gets me to the point I am now.
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
]
}
As far as I can tell, it has something to do with the Electron start URL, because when I removed that from const startUrl in createWindow, running the app using npm start did the same thing as the built Electron app, whereas before using npm would launch the app normally every time.
EDIT after solution:
Modified build in package.json to
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
],
"directories": {
"buildResources": "./public"
}
}
I haven't tested it without this modification so I'm not sure that it's actually necessary.
Start URL was changed to
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../build/index.html'),
protocol: 'file:',
slashes: true,
});
You're supposed to set it up with an html file.
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.html'),
protocol: 'file:',
slashes: true,
});
Your browser window should load the build/index.html on production mode
const isDev = require("electron-is-dev");
if (isDev) {
mainWindow.loadURL(process.env.ELECTRON_START_URL);
} else {
mainWindow.loadFile(path.join("build", "index.html"));
}

How can i suppress logs from webpack when using react hot reloading?

I am using this react redux starter kit https://github.com/coryhouse/pluralsight-redux-starter and i am getting the following outputs in my console
[HMR] connected
I tried to toggle the following fields in the web-pack config to true and false but it doesn't help
noInfo: true,
debug: false,
How can i turn these logs off?
Tried many solutions, the dev server option clientLogLevel: "none" had the closest meaning. But couldn't get it working.
Then I found a workaround:
Run your app with NODE_ENV=development; for that go to package.json and update scripts:
"scripts": {
"build": "webpack",
"start": "NODE_ENV=production webpack-dev-server --progress --inline --hot",
"dev": "NODE_ENV=development webpack-dev-server --progress --inline --hot"
}
modify webpack.config.js:
plugins: [
new webpack.DefinePlugin({
__DEVELOPMENT__: process.env.NODE_ENV !== 'production',
})
],
The DefinePlugin allows you to create global constants which can be
configured at compile time.
OR
Replace global.console.log with a custom console_log that filters out [HMR] and [WDS] logs. See this Github comment.
Add the below code to your development.js (a file which is conditionally appended to the entry in webpack.config.js based on the value process.env.NODE_ENV !== 'production')
(function(global) {
var console_log = global.console.log
global.console.log = function() {
if (!(
arguments.length == 1 &&
typeof arguments[0] === 'string' &&
arguments[0].match(/^\[(HMR|WDS)\]/)
)) {
console_log.apply(global.console,arguments)
}
}
})(window)
npm run dev
If you've used DefinePlugin, then we now have global constant __DEVELOPMENT__ === true on client side. So on every refresh you can do this:
if (__DEVELOPMENT__) {
console.clear();
}
On version >= 4.0.0 of Webpack You can keep the hot reload feature but limit the logs to errors under devServer like below:
devServer: {
hot: true,
client: {
overlay: false,
logging: 'error',
}
...
}
You can find more info about it on https://webpack.js.org/configuration/dev-server/#logging

Resources