electron-userland / electron-builder

A complete solution to package and build a ready for distribution Electron app with “auto update” support out of the box
https://www.electron.build
MIT License
13.7k stars 1.74k forks source link

Production application is blank #2167

Closed janhartmann closed 7 years ago

janhartmann commented 7 years ago

This is my first ever Electron application, so I might have overseen something entirely obvious.

I have made a React application, using Babel and bundled with Webpack3. I am trying to use electron-builder for creating my production application. I am first and foremost completely new to Electron, so I am even unsure on how to debug the running production application.

The issue is, that once I have installed the application, the main window is just the background color of the window - no application is embedded, I can only see the window - no alerts.

My folder structure:

src/
  - /components
  - ...etc
  - index.js
main.js
index.html
webpack.config.prod.js
package.json
...etc

My build steps is:

yarn build which bundles files into ./dist/:

screen shot 2017-10-08 at 08 05 56

yarn pack whichs runs electron-builder and builds the files into ./release/

My configurations is as follows:

{
    "name": "my-application-test",
    "version": "0.0.1",
    "author": "Jan Hartmann",
    "description": "My Application Test",
    "private": true,
    "main": "main.js",
    "scripts": {
        "build":
            "cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
        "start":
            "concurrently \"cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js\" \"cross-env NODE_ENV=development electron -r babel-register ./main.js\"",
        "pack": "electron-builder --dir",
        "dist": "electron-builder",
        "postinstall": "electron-builder install-app-deps"
    },
    "build": {
        "productName": "MyApplication",
        "appId": "com.demo.MyApplicationTest",
        "directories": {
            "buildResources": "resources",
            "output": "release"
        }
    },
    "devDependencies": {
        "babel-core": "^6.26.0",
        "babel-eslint": "^8.0.1",
        "babel-loader": "^7.1.2",
        "babel-plugin-transform-class-properties": "^6.24.1",
        "babel-plugin-transform-object-rest-spread": "^6.26.0",
        "babel-polyfill": "^6.26.0",
        "babel-preset-env": "^1.6.0",
        "babel-preset-react": "^6.24.1",
        "babel-register": "^6.26.0",
        "concurrently": "^3.5.0",
        "cross-env": "^5.0.5",
        "css-loader": "^0.28.7",
        "electron": "^1.7.8",
        "electron-builder": "^19.34.2",
        "electron-devtools-installer": "^2.2.0",
        "eslint": "^4.8.0",
        "eslint-plugin-react": "^7.4.0",
        "extract-text-webpack-plugin": "^3.0.1",
        "file-loader": "^1.1.5",
        "html-webpack-plugin": "^2.30.1",
        "node-sass": "^4.5.3",
        "style-loader": "^0.19.0",
        "url-loader": "^0.6.2",
        "webpack": "^3.6.0",
        "webpack-dev-server": "^2.9.1"
    },
    "dependencies": {
        "babel-runtime": "^6.26.0",
        "classnames": "^2.2.5",
        "color": "^2.0.0",
        "deepmerge": "^1.5.2",
        "global": "^4.3.2",
        "graphql-tag": "^2.4.2",
        "history": "^4.7.2",
        "jss": "^9.0.0",
        "jss-preset-default": "^4.0.1",
        "leaflet": "^1.2.0",
        "moment": "^2.18.1",
        "prop-types": "^15.6.0",
        "react": "^16.0.0",
        "react-apollo": "^1.4.16",
        "react-dom": "^16.0.0",
        "react-hot-loader": "^3.0.0-beta.7",
        "react-jss": "^7.2.0",
        "react-leaflet": "^1.7.0",
        "react-redux": "^5.0.6",
        "react-router-dom": "^4.2.2",
        "react-router-redux": "next",
        "react-tabs": "^2.1.0",
        "react-world-flags": "^0.0.3",
        "redux": "^3.7.2",
        "redux-actions": "^2.2.1",
        "redux-saga": "^0.15.6",
        "sass-loader": "^6.0.6"
    }
}

This is the webpack.config.prod.js file:

const webpack = require("webpack");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    devtool: "cheap-module-source-map",
    context: path.join(__dirname, "./src"),
    target: "electron-renderer",
    entry: {
        app: ["babel-polyfill", "./styles/index.scss", "./index"]
    },
    output: {
        path: path.resolve(__dirname, "./dist"),
        publicPath: "/",
        filename: "[name].bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: ["css-loader", "sass-loader"]
                })
            },
            {
                test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
                use: "file-loader?name=assets/[name].[ext]"
            },
            {
                test: /\.(png|jpg|gif)$/,
                use: "url-loader?limit=8192&name=assets/[name].[ext]"
            },
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: ["babel-loader?cacheDirectory"]
            },
            {
                test: /\.(graphql|gql)$/,
                loader: "graphql-tag/loader"
            }
        ]
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",
            filename: "[name].bundle.js",
            minChunks: Infinity
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false,
                screw_ie8: true,
                conditionals: true,
                unused: true,
                comparisons: true,
                sequences: true,
                dead_code: true,
                evaluate: true,
                if_return: true,
                join_vars: true
            },
            output: {
                comments: false
            }
        }),
        new webpack.HashedModuleIdsPlugin(),
        new webpack.optimize.ModuleConcatenationPlugin(),
        new webpack.NamedModulesPlugin(),
        new webpack.NoEmitOnErrorsPlugin(),
        new ExtractTextPlugin("[name].css"),
        new HtmlWebpackPlugin({
            template: path.join(__dirname, "index.html")
        }),
        new webpack.DefinePlugin({
            "process.env.NODE_ENV": JSON.stringify("production")
        })
    ],
    resolve: {
        alias: {
            actions: path.resolve(__dirname, "src/actions/"),
            assets: path.resolve(__dirname, "src/assets/"),
            components: path.resolve(__dirname, "src/components/"),
            containers: path.resolve(__dirname, "src/containers/"),
            theme: path.resolve(__dirname, "src/theme/"),
            data: path.resolve(__dirname, "src/data/")
        }
    }
};

This is the main.js file in the root of my directory (outside ./src/):

const { app, BrowserWindow } = require("electron");
const path = require("path");

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

// 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", () => {
    if (process.env.NODE_ENV === "development") {
        installExtensions();
    }

    createWindow();
});

// Quit when all windows are closed.
app.on("window-all-closed", () => {
    // On macOS 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", () => {
    // On macOS 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();
    }
});

const createWindow = () => {
    // Create the browser window.
    mainWindow = new BrowserWindow({
        backgroundColor: "#191919",
        width: 1600,
        minWidth: 1600,
        height: 900,
        titleBarStyle: "hiddenInset",
        icon: path.join(__dirname, "resources/icons/64x64.png")
    });

    // and load the index.html of the app.
    if (process.env.NODE_ENV === "development") {
        mainWindow.loadURL("http://localhost:3001");
    } else {
        mainWindow.loadURL(`file://${__dirname}/dist/index.html`);
    }

    mainWindow.once("ready-to-show", () => {
        mainWindow.webContents.openDevTools();
    });

    // Emitted when the window is closed.
    mainWindow.on("closed", () => {
        // 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;
    });
};

const installExtensions = () => {
    const installer = require("electron-devtools-installer");
    const extensions = ["REACT_DEVELOPER_TOOLS", "REDUX_DEVTOOLS"];

    extensions.map(name =>
        installer
            .default(installer[name])
            .then(name => console.log(`Added Extension:  ${name}`))
            .catch(err => console.log("An error occurred: ", err))
    );
};

I am unsure why this is not working, and I hope the community have some great advices to get me running! Let me know if anything is needed more than this.

Kind regards, Jan

cedrickchee commented 7 years ago

Hi. It seems the same (or similar) issue was raised here - https://github.com/react-boilerplate/react-boilerplate/issues/488

I assumed by production you mean your Electron app main process window URL is set to a path to a local HTML file using the file:// protocol. If that is the case, Electron app will not work with React Router using browserHistory. I think you can try changing React Router from using browserHistory to hashHistory, and then it will work fine.

More info about the history JS library is here.

I hope that helps.

dcooney commented 6 years ago

@janhartmann, did you ever figure this one out? I have a very similar setup with the same results <- also my first Electron build.

huanNguyen2204 commented 7 months ago

@cedrickchee It's worked for me. Thank you sir