简体   繁体   中英

React-router browserHistory OVH

👋

I'm trying ReactJS and everything was good until production... I mean, I have a OVH website (it's my own, it's a shared hosting).

On development, I use React Router with the browserHistory and the historyApiFallback for my webpack-dev-server. Everything it's fine.

But when I build my app with webpack, on production, when I reload the page, I get a 404.

I can't run a server like express on my website, it's a shared hosting. Any solutions?


build.js

const webpack = require('webpack')
const conf = require('./webpack.prod')
const ora = require('ora')
const spinner = ora('Building...')
const path = require('path')
const root = path.resolve(__dirname, '../')
require('shelljs/global')

spinner.start()
rm('-rf', 'build')
mkdir('-p', path.join(root, 'build'))
cp(path.join(root, 'source/index-build.html'), path.join(root, 'build/index.html'))

webpack(conf, (err, stats) => {
  spinner.stop()
  if (err) throw err

  process.stdout.write(`${stats.toString({
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  })}\n`)
})


webpack.prod.js

const webpack = require('webpack')
const config = require('./webpack.base')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('bundle.css')

config.plugins = config.plugins.concat([
  extractCSS,
  new webpack.optimize.UglifyJsPlugin({
    comments: false,
    warnings: false,
  }),
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
  })
])

const cssLoaders = config.module.loaders[0].loaders
config.module.loaders[0].loaders = null
config.module.loaders[0].loader = extractCSS.extract(cssLoaders.slice(1, cssLoaders.length))

module.exports = config


webpack.base.js

const path = require('path')
const root = path.resolve(__dirname, '../')

const StyleLintPlugin = require('stylelint-webpack-plugin')

module.exports = {
  entry: {
    app: [
      path.join(root, 'source/styles/styles.scss'),
      path.join(root, 'source/scripts/index.js')
    ]
  },
  output: {
    path: path.join(root, 'build'),
    filename: 'bundle.js',
    publicPath: '/build/'
  },
  module: {
    preLoaders: [{
      test: /\.js$/,
      exlude: /(node_modules|bower_components)/,
      loader: 'eslint'
    }],
    loaders: [{
      test: /\.scss$/,
      loaders: ['style', 'css', 'sass', 'sass-resources']
    }, {
      test: /\.js$/,
      exlude: /(node_modules|bower_components)/,
      loader: 'babel'
    }, {
      test: /\.(jpg|jpeg|png|gif|svg)$/,
      loader: 'url',
      query: {
        limit: 100,
        name: 'images/[name]-[hash:16].[ext]'
      },
      include: path.join(root, 'source/static/images')
    }, {
      test: /\.(woff2|ttf|eog|svg)$/,
      loader: 'file',
      query: {
        limit: 1,
        name: 'fonts/[name]-[hash:16].[ext]'
      },
      include: path.join(root, 'source/static/fonts')
    }, {
      test: /\.json$/,
      loader: 'url',
      query: {
        name: 'json/[name]-[hash:16].[ext]'
      },
      include: path.join(root, 'source/static/json')
    }, {
      test: /\.mp4$|\.webm$/,
      loader: 'url',
      query: {
        limit: 3000,
        name: 'videos/[name]-[hash:16].[ext]'
      },
      include: path.join(__dirname, 'source/static/video')
    }]
  },
  plugins: [
    new StyleLintPlugin({
      files: './source/**/*.scss'
    })
  ],
  sassResources: [
    path.join(root, 'source/styles/_variables.scss'),
    path.join(root, 'source/styles/_functions.scss'),
    path.join(root, 'source/styles/_mixins.scss')
  ],
  eslint: {
    configFile: path.join(root, '.eslintrc'),
    formatter: require('eslint-friendly-formatter')
  },
  sasslint: {
    configFile: path.join(root, '.sass-lint.yml')
  }
}


index.js

import React from 'react'
import { createStore, applyMiddleware, compose } from 'redux'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { Router, Route, browserHistory, IndexRedirect } from 'react-router'
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'

import App from './containers/App'
import Projects from './components/Projects'
import Work from './components/Work'
import Profile from './components/Profile'

import routes from './constants/routes'
import reducers from './reducers'

const middleware = [
  thunk,
  routerMiddleware(browserHistory)
]

// Create stores
const store = createStore(
  reducers,
  compose(
    applyMiddleware(...middleware),
    window.devToolsExtension ? window.devToolsExtension() : f => f
  )
)

// History
const history = syncHistoryWithStore(browserHistory, store)

render ((
  <Provider store={store}>
    <Router history={history}>
      <Route path={routes.ROOT} component={App}>

        <IndexRedirect to="/door-opener" />

        <Route path={routes.PROFILE} component={Profile} />
        <Route path={routes.PROJECTS} component={Projects} />
        <Route path={routes.WORK} component={Work} />
      </Route>
    </Router>
  </Provider>),
  document.getElementById('root')
)

if (module.hot) {
  // Enable Webpack hot module replacement for reducers
  module.hot.accept('./reducers', () => {
    const nextReducer = require('./reducers/index').default
    store.replaceReducer(nextReducer)
  })
}

If your shared host won't let you configure your server, you won't be able to do this, you need to be able to reroute the URLs.

https://github.com/ReactTraining/react-router/blob/master/docs/guides/Histories.md

I found the solution. It was just a htaccess issue.

.htaccess

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM