I've been working in this app for weeks and now I'm trying to packit to distribute. When I'm in dev it works just fine, but in production I only get a blank page. I've been lookig for solution in every post here but I can't get it.
This is my package.json
{
"name": "triviapp",
"author": "trivify",
"version": "1.0.0",
"private": true,
"main": "public/electron.js",
"dependencies": {
"#fortawesome/fontawesome-svg-core": "^6.2.0",
"#fortawesome/free-solid-svg-icons": "^6.2.0",
"#fortawesome/react-fontawesome": "^0.2.0",
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#testing-library/user-event": "^13.5.0",
"docxtemplater": "^3.31.6",
"electron-is-dev": "^2.0.0",
"jimp": "^0.16.2",
"lodash": "^4.17.21",
"mongoose": "^6.7.0",
"nodejs-pptx": "^1.0.1",
"pizzip": "^3.1.3",
"ppt-template": "^1.0.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.2",
"react-scripts": "5.0.1",
"translate": "^1.4.1",
"web-vitals": "^2.1.4",
"xlsx-template": "^1.3.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron-dev": "concurrently \"set BROWSER=none&& npm start\" \"wait-on
http://localhost:3000 && electron .\"",
"hotel-dev": "concurrently \"set BROWSER=none&& npm start\" \" electron .\"",
"dist": "electron-builder"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"babel-polyfill": "^6.26.0",
"concurrently": "^7.5.0",
"electron": "^21.2.0",
"electron-builder": "^23.6.0",
"wait-on": "^6.0.1"
},
"build": {
"appId": "com.trivify.triviapp",
"productName": "TriviApp",
"target": "NSIS",
"extends": null,
"nsis": {
"allowToChangeInstallationDirectory": true,
"oneClick": false
},
"directories": {
"buildResources": "resources",
"output": "release"
}
}
}
This is my electron.js
const electron = require('electron');
const app = electron.app;
const { BrowserWindow, ipcMain } = electron;
const path = require('path');
const isDev = require('electron-is-dev');
const { generateTrivia, createFolderWithImgs } = require('../src/logic/func');
const { createDoc } = require('../src/logic/createDoc');
const { createPPT } = require('../src/logic/createPPT');
const { getPreguntas, getRascas, addQuestionToBD, getBaresIsla, newIslandInDB, getIslaCodes }
= require('../src/logic/dbfuncs');
const { connectDB } = require('../src/db');
const {createRascas} = require('../src/logic/createRascas');
const { createTicketIsla } = require('../src/logic/createTicketsIsla');
const url = require('url');
connectDB();
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1300,
height: 900,
center: true,
useContentSize: true,
minHeight: 600,
minWidth: 1000,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
webSecurity: false
}
});
mainWindow.loadURL(isDev ? 'http://localhost:3000' : url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
if (isDev) {
// Open the DevTools.
//BrowserWindow.addDevToolsExtension('<location to your react chrome extension>');
// mainWindow.webContents.openDevTools();
}
mainWindow.on('closed', () => mainWindow = null);
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
This is my index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HashRouter } from "react-router-dom"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HashRouter >
<App />
</HashRouter>
</React.StrictMode>
);
and my app.js
import './stylesheets/App.css';
import { Route, Routes } from "react-router-dom";
import Home from './views/Home';
import Trivial from './views/Trivial';
import DataBases from './views/Databases';
import Rascas from './views/Rascas';
import IslaMisterio from './views/IslaMisterio';
import Facturas from './views/Facturas';
function App() {
return (
<div className='App'>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/trivial' element={<Trivial />} />
<Route path='/pasapalabra' element={<Home />} />
<Route path='/isla' element={<IslaMisterio />} />
<Route path='/rasca' element={<Rascas />} />
<Route path='/facturas' element={<Facturas />} />
<Route path='/databases' element={<DataBases />} />
</Routes>
</div>
);
}
export default App;
If you have any idea of why is this happening, please help!
With CRA, you need to add homepage to your package.json or your app will not work correctly in production. For an Electron app, you can use:
"homepage": "./"
If you have routing, you also need to check that you are using <HashRouter> and not <BrowserRouter>. For reference, here is a question about this.
Related
My app works perfectly in local, without errors, but when I try to deploy it on netlify or github pages, when I open it, the page is blank and many errors are displayed in the console.
The error says
TypeError: can't access property "length", e is undefined
where e corresponds to items (which is a state).
If I remove these lines of code, I get another error that always concerns items: the problem this time is with items.some, where items is null again.
Whatever I try to do items always result null.
I tried console.log(items) in many component files and in all of them the result is null.
This is the netlify link where you can see the error:
https://celadon-otter-917b4e.netlify.app/
Navbar.js, where the error is located:
import { Link } from 'react-router-dom';
import Searchbar from './Searchbar';
import { useContext } from 'react';
import FavoritesContext from '../FavoritesContext';
function Navbar() {
const { items } = useContext(FavoritesContext);
return (
<div className='navbar'>
<Link to={'/'} style={{ textDecoration: 'none' }}>
<div className='logo-container'>
<img src="/foglia.png" alt="logo" className='logo'/>
<h3>just<span>vegetables</span></h3>
</div>
</Link>
<Searchbar />
<Link to={'/favorites/'} style={{ textDecoration: 'none' }}>
<h4 className='favor'>Favorites: <span>{items.length}</span></h4>
</Link>
</div>
)
}
export default Navbar;
FavoriteContext.js:
import React, { createContext, useState, useEffect } from "react";
const FavoritesContext = createContext();
export function FavoritesProvider({ children }) {
const [ items, setItems ] = useState([]);
useEffect(() => {
const recipesFavorites = JSON.parse(localStorage.getItem('favorites-recipes'));
setItems(recipesFavorites);
}, []);
const saveToLocalStorage = (item) => {
localStorage.setItem('favorites-recipes', JSON.stringify(item))
}
const addToFavorites = (title, image, id, favorite) => {
if (!favorite) {
const newFavoriteList = [...items, { title, image, id }]
setItems(newFavoriteList);
saveToLocalStorage(newFavoriteList);
};
};
const removeFromFavorites = (title, image, id, favorite) => {
if (favorite) {
const newFavoriteList = items.filter((fav) => fav.id !== id);
setItems(newFavoriteList);
saveToLocalStorage(newFavoriteList);
};
};
return (
<FavoritesContext.Provider value={{ items, setItems, addToFavorites, removeFromFavorites }}>
{children}
</FavoritesContext.Provider>
)
}
export default FavoritesContext;
Card.js:
import { Link } from 'react-router-dom';
import FavoritesContext from '../FavoritesContext';
function Card({ title, image, id }) {
const { addToFavorites } = useContext(FavoritesContext);
const { removeFromFavorites } = useContext(FavoritesContext);
const { items } = useContext(FavoritesContext);
const checkIsAdd = () => {
if(items.some((val) => val.id === id)) {
return true;
}};
const [favorite, setFavorite] = useState(checkIsAdd);
const isInFavorites = (id) => {
return (
<img src='../cuore-pieno.png' alt="like" className='favorite blue' onClick={() => {removeFromFavorites(title, image, id, favorite); toggle()}}/>
)
}
const toggle = () => {
isInFavorites(id);
setFavorite(!favorite);
}
return (
<div className='card'>
{!favorite ? <img src='../cuore-vuoto.png' alt="like" className='favorite' onClick={() => {addToFavorites(title, image, id, favorite); toggle()}}/> : isInFavorites(id)}
<Link to={'/recipe/' + id}>
<img src={image} alt='' className='card-image'/>
<div className='card-info-cnt'>
<p className='card-title'>{title}</p>
</div>
</Link>
</div>
)
}
export default Card;
package.json
{
"name": "projetto-react",
"version": "0.1.0",
"homepage": "https://michela-z.github.io/justVegetables",
"main": "index.js",
"dependencies": {
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#testing-library/user-event": "^13.5.0",
"axios": "^0.27.2",
"lodash": "^4.17.21",
"node-env-webpack-plugin": "^1.1.0",
"process": "^0.11.10",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-icons": "^4.4.0",
"react-router-dom": "^6.3.0",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d dist",
"serve": "webpack-dev-server --mode development --open --hot",
"start": "webpack-dev-server",
"build": "webpack --mode production",
"test": "react-scripts test",
"eject": "react-scripts eject",
"webpack": "webpack",
"webpack-dev-server": "webpack-dev-server",
"dev": "npm run webpack-dev-server -- --env mode=development",
"prod": "npm run webpack -- --env mode=production"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#babel/core": "^7.18.13",
"#babel/preset-env": "^7.18.10",
"#babel/preset-react": "^7.18.6",
"babel-loader": "^8.2.5",
"css-loader": "^6.7.1",
"file-loader": "^6.2.0",
"gh-pages": "^4.0.0",
"html-webpack-plugin": "^5.5.0",
"source-map-loader": "^4.0.0",
"url-loader": "^4.1.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.10.0"
}
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const port = process.env.PORT || 3000;
module.exports = {
mode: 'development',
entry: {
index: {
import: './src/index.js',
dependOn: 'shared',
},
another: {
import: './src/another-module.js',
dependOn: 'shared',
},
shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.join(__dirname, '/dist')
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
}
}
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
devServer: {
host: 'localhost',
port: port,
historyApiFallback: true,
open: true
},
optimization: {
runtimeChunk: 'single',
},
};
I'm new to programming, this is my first react app, I tried everything that was in my ability.
Check if there item present before checking its length {items.length}
you can achieve this by
{item && item.length} or
{items?.length}
this will get rid of the errors displayed in live deploy
I am using the following packages and have installed tailwindcss in the following project folder /home/admin/Desktop/Code/main_project/client/package.json:
{
"name": "react-app",
"version": "1.0",
"private": true,
"dependencies": {
"babel-eslint": "10.0.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",
"react-router": "^6.3.0",
"react-scripts": "3.2.0",
"redux": "^4.1.1",
"redux-thunk": "^2.3.0",
"web-vitals": "^1.0.1",
"web3": "^1.6.1",
"web3-eth-contract": "^1.5.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.7",
"postcss": "^8.4.14",
"tailwindcss": "^3.0.24"
}
}
My tailwind.config.js looks like the following:
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
As you can see my react-project lies in a subfolder.
My postcss.config.js looks like the following:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
This is my index.css:
#tailwind base;
#tailwind components;
#tailwind utilities;
In my index.js I am loading my index.css:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from "./redux/store";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
My App.js looks like the following:
import React, { useEffect, useState, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { connect } from "./redux/blockchain/blockchainActions";
import { fetchData } from "./redux/data/dataActions";
import "./App.css";
function App() {
const dispatch = useDispatch();
const blockchain = useSelector((state) => state.blockchain);
const data = useSelector((state) => state.data);
const [CONFIG, SET_CONFIG] = useState({
CONTRACT_ADDRESS: "",
SCAN_LINK: "",
NETWORK: {
NAME: "",
SYMBOL: "",
ID: 0,
},
NFT_NAME: "",
SYMBOL: "",
MAX_SUPPLY: 1,
WEI_COST: 0,
DISPLAY_COST: 0,
GAS_LIMIT: 0,
MARKETPLACE: "",
MARKETPLACE_LINK: "",
SHOW_BACKGROUND: false,
});
const getData = () => {
if (blockchain.account !== "" && blockchain.smartContract !== null) {
dispatch(fetchData(blockchain.account));
}
};
const getConfig = async () => {
const configResponse = await fetch("/config/config.json", {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
const config = await configResponse.json();
SET_CONFIG(config);
};
useEffect(() => {
getConfig();
}, []);
useEffect(() => {
getData();
}, [blockchain.account]);
return (
<>
<h1 className="text-3xl font-bold underline">Welcome</h1>
<>
);
}
export default App;
However, the components in my App.js do not get rendered with tailwindcss.
Any suggestions what I am doing wrong?
I appreciate your replies!
I am using React's Context API to call setCurrentUser below. But it gives me this error:
TypeError: setCurrentUser is not a function.
Upon logging console.log(useContext(globalContext)), I get the empty object {}.
I have manually converted my project from TS(where it worked by specifying setCurrentUser as type Dispatch) to JS, so I am not sure if that broke something...at least my react and react-dom packages should be current.
How do we make this work with JS? Thanks
Router.jsx - where I am calling setCurrentUser
import React, { useContext, useEffect } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import LoginPg from "../pages/LoginPg/LoginPg";
import ErrorHandler from "./ErrorHandler";
import ErrorPg from "../pages/ErrorPg/ErrorPg";
import useGet from "../../server_api/useGet";
import ProtectedRoute from "./ProtectedRoute";
import HomePg from "../pages/HomePg/HomePg";
import { globalContext } from "../../store/context/globalContext";
import CalendarPg from "../pages/Calendar/CalendarPg";
function Router() {
const { currentUser, setCurrentUser } = useContext(globalContext);
const [doGet] = useGet();
let user;
console.log(useContext(globalContext)); // <==== logs: {}
useEffect(() => {
doGet("auth/authenticate", (res) => {
if (res) {
user = res.username;
setCurrentUser(res);
} else {
console.log("Router: user not authenticated");
}
});
}, []);
return (
<BrowserRouter>
<ErrorHandler>
<Switch>
<Route path="/error" component={ErrorPg} />
<Route path="/login" component={LoginPg} />
<ProtectedRoute
path="/calendar"
Component={CalendarPg}
isAuth={currentUser}
key="uniquevalue"
/>
<ProtectedRoute path="/" Component={HomePg} isAuth={currentUser} />
</Switch>
</ErrorHandler>
</BrowserRouter>
);
}
export default Router;
globalContext.jsx
import { createContext, useState } from "react";
export const globalContext = createContext({});
export default function GlobalContext(props) {
const [currentUser, setCurrentUser] = useState(null);
return (
<globalContext.Provider value={{ currentUser, setCurrentUser }}>
{props.children}
</globalContext.Provider>
);
}
package.json
{
"name": "test",
"version": "0.1.0",
"private": true,
"homepage": "/",
"dependencies": {
"#fullcalendar/daygrid": "^5.9.0",
"#fullcalendar/interaction": "^5.9.0",
"#fullcalendar/react": "^5.9.0",
"#fullcalendar/timegrid": "^5.9.0",
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"antd": "^4.16.13",
"axios": "^0.21.1",
"bootstrap": "^5.1.1",
"font-awesome": "^4.7.0",
"fullcalendar": "^5.9.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"query-string": "^4.3.4",
"react": "^17.0.2",
"react-calendar": "^3.4.0",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-modal": "^3.14.3",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"sass": "^1.39.2",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"cypress": "npx cypress open"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"cypress": "^7.5.0"
}
}
You need the consumer (Router) to be a child of the provider (GlobalContext).
Also your component names should start with an Upper case.
import { GlobalContext } from "../../store/context/GlobalContext";
const App = () => {
const [currentUser, setCurrentUser] = useState(DEFAULT_USER);
return (
<GlobalContext.Provider value={{ currentUser, setCurrentUser }}>
<Router />
</GlobalContext.Provider>
);
};
I am working now upon an Electron + React-JS app, and have to create a distribution build. The problem is that after creating that build and launching the resulted file (in our case the compiled app), the app shows me a blank screen without rendering any of ./src folder's content. Everything's working well when launching Electron in dev mode.
For some reference, I'll attach the contents of my package.json, electron's main.js and React's index.js and App.js files.
Package.json
{
...
"build": {
"appId": ...,
"mac": {
"category": ...
},
"files": [
"build/**/*",
"node_modules/**/*"
],
"directories": {
"buildResources": "assets"
}
},
"main": "public/electron.js",
"homepage": "./",
"dependencies": {
"#reach/router": "^1.2.1",
"apexcharts": "^3.10.1",
"apisauce": "^1.1.1",
"cross-env": "^6.0.3",
"electron-is-dev": "^1.1.0",
"formik": "^2.0.4",
"moment": "^2.24.0",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react-loading-overlay": "^1.0.1",
"react-notification-system": "^0.2.17",
"react-pin-input": "^0.9.0",
"react-redux": "^7.1.3",
"react-scripts": "3.2.0",
"react-table": "^6.10.3",
"redux": "^4.0.4",
"redux-persist": "^6.0.0",
"reduxsauce": "^1.1.1",
"seamless-immutable": "^7.1.4",
"yup": "^0.27.0"
},
"scripts": {
"react-start": "react-scripts start",
"react-build": "react-scripts build",
"react-test": "react-scripts test --env=jsdom",
"react-eject": "react-scripts eject",
"electron-postinstall": "electron-builder install-app-deps",
"electron-start": "concurrently \"cross-env BROWSER=none yarn react-start\" \"wait-on http://localhost:3000 && electron .\"",
"electron-build": "electron-builder",
"release": "yarn react-build && electron-builder --publish=always",
"build": "yarn react-build && yarn electron-build",
"build-mw": "yarn react-build && electron-builder -mw"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"concurrently": "^5.0.0",
"electron": "^7.1.1",
"electron-builder": "^22.1.0",
"wait-on": "^3.3.0"
}
}
Electron main.js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
const isDev = require('electron-is-dev');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({width: 900, height: 680});
mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`);
mainWindow.on('closed', () => mainWindow = null);
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
React index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
React App.js
import React from 'react';
import './App.css';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import {persistStore} from 'redux-persist';
import {PersistGate} from 'redux-persist/integration/react';
import Navigation from './Navigation';
import {RootReducer} from './Redux/Root.Reducer';
const store = createStore(RootReducer);
const persistor = persistStore(store);
function App() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Navigation />
</PersistGate>
</Provider>
);
}
export default App;
P.S. As opposed to the tutorials found on the internet about linking Electron with React-JS, I've placed Electron's main.js file under ./public directory, in my React project.
Learning React right now tried to use react-router for page routing, but because of some reasons I always see the blank page instead of rendered component.
I'm using webpack-dev-server as dev server.
Looking for your help and advices
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="dist/css/app.css">
</head>
<body>
<div id="root"></div>
<script src="dist/js/app.js"></script>
</body>
</html>
app.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route, IndexRoute, hashHistory } from "react-router";
import App from './Pages/App';
import Archives from './Pages/Archives';
import Features from './Pages/Features';
import Settings from './Pages/Settings';
const app = document.getElementById('root');
// ReactDOM.render(<Layout/>, app);
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Features}/>
<Route path='archives' component={Archives}/>
<Route path='settings' component={Settings}/>
</Route>
</Router>
, app);
App component
import React from 'react';
import { Link } from 'react-router'
export default class App extends React.Component{
render(){
return (
<div>
<h1>App</h1>
<Link to="/archives">Archives</Link>
<Link to="/settings">Settings</Link>
{this.props.children}
</div>
);
}
}
package.json
{
"name": "Planner",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"dependencies": {
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-react-html-attrs": "^2.0.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"history": "^4.6.1",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-router": "^4.1.1",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.4"
},
"devDependencies": {},
"scripts": {
"dev": "webpack-dev-server --content-base --inline --hot",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
UPDATED:
Webpack config
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: path.join(__dirname, "src"),
devtool: debug ? "inline-sourcemap" : null,
entry: "./js/app.js",
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'],
}
}
]
},
output: {
path: path.resolve(__dirname, 'dist/js'),
filename: "app.js",
publicPath: '/dist/js/'
},
plugins: debug ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
],
};