react-everywhere/re-start

Electron issues

thorakmedichi opened this issue · 15 comments

Step 2: Describe your environment

  • template name : re-start
  • template version : Unsure... what existed a Feb 2019
  • react-native version: 55.4 (as per what the template had)
  • OS :Linux
  • Platform causing error: Electron

Step 3: Describe the problem (try to include screenshots):

Running yarn electron-builder produces my AppImage but the screen is blank
Running yarn electron-pack (yarn build -c.extraMetadata.main=build/electron.js) errors out with a ton of errors. Top of the list is

Application entry file "build/electron.js" in the "/home/thorakmedichi/Development/Projects/stormfree/day-tracer/dist/linux-unpacked/resources/app.asar" does not exist. Seems like a wrong configuration.
    at error (/home/thorakmedichi/Development/Projects/stormfree/day-tracer/node_modules/app-builder-lib/out/asar/asarFileChecker.js:44:14)

Am I missing something not outlined in your documentation?

Expected Results:

An electron app that works, dev or production.

package.json

{
  "name": "testing",
  "version": "0.1.12",
  "author": "thorakmedichi",
  "main": "./index.electron.js",
  "homepage": "./",
  "scripts": {
    "android": "./node_modules/.bin/react-native run-android",
    "ios": "./node_modules/.bin/react-native run-ios",
    "web": "node scripts/start.js",
    "build": "node scripts/build.js",
    "lint": "eslint . --ext .js",
    "electron-dev": "concurrently \"BROWSER=none yarn react-scripts start\" \"wait-on http://localhost:3000 && electron .\"",
    "electron-pack": "build -c.extraMetadata.main=build/electron.js",
    "electron-build": "electron-builder",
    "preelectron-pack": "yarn build",
   },
  "build": {
    "appId": "com.example.electron-cra",
    "files": [
      "build/**/*",
      "node_modules/**/*",
      "public/*",
      "./index.electron.js"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },

  ....etc

Resolved pack errors by changing

"electron-pack": "build -c.extraMetadata.main=build/electron.js",

to

"electron-pack": "build -c.extraMetadata.main=./index.electron.js",

Screen still blank.

Upon opening the build folder and running the index.html file locally it also is a blank screen. No errors showing in the dev console.

So my white screen appears to have been an issue with react-router

It would appear that BrowserHistory wont work with electron so I had to change to HashHistory

Can you provide a pull-request with your changes to have a record of them?

Can you provide a pull-request with your changes to have a record of them?

To be honest I don't know how this repo is put together to even decide where / how to make the PR for you. I just did a react-native init <Your Project Name> --template re-start and fixed from there.

I had to fix jest issues, webpack issues, package.json issues, index.electron.js issues etc AFTER that init.

I am happy to outline what we did though for the electron side if you want to add the PR yourself.

In short the yarn electron that your readme.md shows only loaded a loader, then we had to drag the index.electron.js file into the app loader... and then it only worked for local testing. Zero use in the real world where you need to build to give to other people without dev environments.

In package.json we added these scripts:

"build": "node scripts/build.js",
"electron-build:linux": "yarn build && electron-builder -l",
"electron-build:windows": "yarn build && electron-builder -w",
"electron-build:mac": "yarn build && electron-builder -m",

Then we added the "build" to package.json

"build": {
    "appId": "com.example.electron-cra",
    "files": [
      "dist/**/*",
      "build/**/*",
      "node_modules/**/*",
      "src/assets/**/*",
      "public/*",
      "./index.electron.js"
    ],
    "directories": {
      "buildResources": "./src/common/assets"
    },
    "win": {
      "icon": "./src/common/assets/app-icons/png/512x512.png"
    },
    "linux": {
      "icon": "./src/common/assets/app-icons/png/512x512.png"
    },
    "mac": {
      "icon": "./src/common/assets/app-icons/png/osx-icon-512x512.png"
    }
  },

Then we changed index.electron.js line 24 which was:

mainWindow.loadURL('http://localhost:3000');

To be

mainWindow.loadURL(`file://${path.join(__dirname, './build/index.html')}`);

Basically the following package.json command did nothing but cause issues so we just abandoned it all together

"electron-pack": "build -c.extraMetadata.main=./index.electron.js",

There was some issue in doing the electron build where it didn't like the assets folder outside of the /src dir so we moved them into /src/common/assets to share between all platforms.

We did a lot more than that but that is the core of the electron fixes we needed to do. I just cant remember every thing that was done as a whole for us to make re-start work for our specific use case

For our router issues - well we use react-navigation for RN as it has better animations and router handling than react-native-router. Basically our entire team thought react-native-router was kinda crap compared to alternatives.

For web we used react-router because its solid for web. To accomplish this we had to build some common interfaces and take advantage of the .web.js notation.

The trick was that RNW didn't like react-router's BrowserHistory for Electron builds so we had to use HashHistory instead.

So we basically had
navigator.web.js

import { history } from './history';

/**
 * Used with navigator.js to make a universal command to navigate from components
 * This makes our main code platform agnostic
 *
 * @param {string} routeName The screen to navigate to
 * @param {object} params Any extra data you want to pass to the route
 */
const navigate = (routeName, params = {}) => {
    history.push({
        pathname: routeName,
        state: params
    });
};

const currentRoute = () => history.location.pathname.replace(/\//, '');

const closeDrawer = () => null;

export default {
    navigate,
    currentRoute,
    closeDrawer
};

and navigator.js

import { NavigationActions, DrawerActions } from 'react-navigation';

let navigator;

/**
 * Creates a ref callback to the App.js AppStack
 * @param {string} navigatorRef
 */
const setTopLevelNavigator = (navigatorRef) => {
    navigator = navigatorRef;
}

/**
 * Gets the current screen from react-navigation
 * @param {object} navigationState
 * @returns {*}
 */
const getActiveRouteName = (navigationState) => {
    if (isEmpty(navigationState)) {
        return null;
    }
    const route = navigationState.routes[navigationState.index];
    // dive into nested navigators
    if (route.routes) {
        return getActiveRouteName(route);
    }
    return route.routeName;
};

/**
 * Used with navigator.web.js to make a universal command to navigate from components
 * This makes our main code platform agnostic
 *
 * @param {string} routeName The screen to navigate to
 * @param {object} params Any extra data you want to pass to the route
 */
const navigate = (routeName, params) => {
    navigator.dispatch(
        NavigationActions.navigate({
            routeName,
            params,
        })
    );
}

const currentRoute = () => {
    if (navigator) {
        return getActiveRouteName(navigator.state.nav);
    }

    return null;
}

const closeDrawer = () =>  navigator.dispatch(DrawerActions.closeDrawer());

export default {
    navigate,
    currentRoute,
    setTopLevelNavigator,
    closeDrawer
};

history.js

/**
 * Creates a global history object for navigating web routes
 */
// BrowserHistory does not work with Electron so we have to use HashHistory
import createHashHistory from 'history/createHashHistory';

export const history = createHashHistory();

and our router.web.js file had

import { history } from './history';

<Router history={history}>
//.....
</Router>

Then anywhere in our app we could just do things like NavigationService.navigate('MyScreen') and regardless of the platform it knew what navigation system to use.

For our jest testing we found that the tests would lock up on us all the time so we changed package.json to be

"test": "npm run test:native && npm run test:web",
"test:web": "node scripts/test.js --config \"./config/web.jest.config.js\" --detectOpenHandles --maxWorkers=10",
"test:native": "node scripts/test.js --config \"./config/native.jest.config.js\" --ci --coverage --detectOpenHandles --maxWorkers=10",

Note the --detectOpenHandles --maxWorkers=10

Also we use react-native-elements (as I think a lot of people do) so we had to add the following to the webpack.config.xxxxx.js to the include below line 285

// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript and some ESnext features.
`${paths.appNodeModules}/react-native-elements`,
`${paths.appNodeModules}/react-native-vector-icons`,
`${paths.appNodeModules}/react-native-ratings`,
`${paths.appNodeModules}/react-native-status-bar-height`,

We also had to add the following to src/index.js

import iconFont from 'react-native-vector-icons/Fonts/MaterialIcons.ttf';

const iconFontStyles = `
    @font-face {
        src: url(${iconFont}) format('truetype');
        font-family: MaterialIcons;
    }
`;

// Create stylesheet
const style = document.createElement('style');
style.type = 'text/css';

if (style.styleSheet) {
    style.styleSheet.cssText = iconFontStyles;
} else {
    style.appendChild(document.createTextNode(iconFontStyles));
}

// Inject stylesheet
document.head.appendChild(style);

There was more... but that does the broad sweep of changes to basically get us running.

Oh and one more... we found we had to change babel.config.js to

module.exports = function (api) {
    api.cache(true);
    return {
        presets: [['module:metro-react-native-babel-preset'], ['react-app']],
        ignore: ['node_modules/art/core/color.js'],
        plugins: [
            ['module-resolver', {
                'alias': {
                    '^react-native$': 'react-native-web'
                }
            }]
        ],
    };
};

The re-start template is obsolete, the new build process is to install the re-base template and all the customized ones on top of it, and after that exec the finish-install script.

@amoghbanta can you provide me permissions on npm to fix that? I've already done a script to publish all new templates at once.

@piranna, done!
You have the access now. 😄

Is it still give me login errors...

403 Forbidden - PUT https://registry.npmjs.org/react-native-template-re-base - You do not have permission to publish "react-native-template-re-base". Are you logged in as the correct user?

I'm logged in npm as piranna.

The re-start template is obsolete, the new build process is to install the re-base template and all the customized ones on top of it, and after that exec the finish-install script.

okay good to know. We started this project about 1.5 months - 2 months ago and the readme.md that I see here now today is not what it was when we first found your library.

Cheers

Is it still give me login errors...

403 Forbidden - PUT https://registry.npmjs.org/react-native-template-re-base - You do not have permission to publish "react-native-template-re-base". Are you logged in as the correct user?

I'm logged in npm as piranna.

Hey, @piranna, I just checked, you have admin rights on react-everywhere npm packages. If you could please check once again at your site, that'd be great.

NOW it worked 🎉 All published as 0.4.1 version, thanks! :-D