web-dev-qa-db-fra.com

Comment intégrer une application React à un sous-répertoire sur un serveur?

J'ai développé une application React sur mon hôte local. Je veux le copier sur un serveur dans un sous-répertoire appelé Vensa.

Mon fichier de configuration webpack ressemble à ceci.

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: 'build',
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style', 'css!sass')
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css')
      },
      {
        test: /\.(png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
        loader: 'url'
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('vensa-dashboard.css')
  ],
  devServer: {
    historyApiFallback: true,
    contentBase: './build'
  }
};

Le fichier index.html ressemble à ceci ...

<!DOCTYPE html>
<html>
<head>
  <title>Vensa Development Test</title>
  <link rel="stylesheet" href="/vensa-dashboard.css">
</head>
<body>
  <div class="container"></div>
  <script src="/bundle.js"></script>
</body>
</html>

et mon fichier routes.js est ...

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import VensaDashboard from './components/VensaDashboard';
import Inbox from './components/Inbox';
import Todo from './components/Todo';
import Home from './components/Home';

export default (
  <Route path="/" component={VensaDashboard}>
    <IndexRoute component={Home} />
    <Route path="/message" component={Inbox} />
    <Route path="/todo/:todoPage" component={Todo} />
  </Route>
);

Cependant, si je ne fais que lancer webpack -p et copier les 3 fichiers dans ce sous-répertoire, cela ne fonctionne pas car le chemin racine est / et il ne peut pas trouver les fichiers js et css. Je ne suis pas sûr de ce que (la meilleure façon) de changer (probablement un ou tous ces 3 fichiers) pour le faire fonctionner dans un sous-répertoire?

Le code source complet de l'application est ici au cas où cela aiderait.

Merci!

13
magician11

Si vous utilisez React Router v4, vous devriez pouvoir le définir en utilisant basename = {foobar}.

<Router history={browserHistory} basename={'foobar'}>
  <Route path="/" component={App} />
</Router>

Lien vers la documentation: https://reacttraining.com/react-router/web/api/BrowserRouter

Remarque: si vous utilisez create-react-app dans un sous-répertoire, vous voudrez également définir "homepage": "/foobar/", dans votre fichier package.json. La production se situe donc sur le bon chemin.

21
trenthogan

Je devais faire quelque chose de similaire récemment afin de faire fonctionner une application de réaction dans un sous-répertoire. Essayez ce qui suit et voyez comment vous vous en sortez.

import React from 'react';
import { Router, Route, IndexRoute, useRouterHistory  } from 'react-router';
import { createHistory } from 'history';
import VensaDashboard from './components/VensaDashboard';
import Inbox from './components/Inbox';
import Todo from './components/Todo';
import Home from './components/Home';

// specify basename below if running in a subdirectory or set as "/" if app runs in root
const appHistory = useRouterHistory(createHistory)({
  basename: "/vensa"
});

export default (
  <Router history={appHistory} />
    <Route path="/" component={VensaDashboard}>
      <IndexRoute component={Home} />
      <Route path="/message" component={Inbox} />
      <Route path="/todo/:todoPage" component={Todo} />
    </Route>
  </Router>
);

Vous devrez peut-être également mettre à jour le chemin d'accès à votre fichier bundle.js dans index.html, comme indiqué ci-dessous

<!DOCTYPE html>
<html>
<head>
  <title>Vensa Development Test</title>
  <link rel="stylesheet" href="/vensa-dashboard.css">
</head>
<body>
  <div class="container"></div>
  <script src="bundle.js"></script>
</body>
</html>
2
Rusta

En ajoutant à la réponse de trenthogan, nous pouvons assigner basename à location.pathname

const loc = window.location || {};
<Router history={browserHistory} basename={loc.pathname || 'foobar'}>
  <Route path="/" component={App} />
</Router>

Avec ce changement, l'application fonctionnera même si le chemin du sous-répertoire change à l'avenir. 

1

Utilisez le html-webpack-plugin pour générer votre index.html final avec les noms de bundles corrects automatiquement injectés.

Puis définissez output.publicPath dans votre configuration Webpack pour indiquer à Webpack le sous-répertoire dans lequel vos actifs seront déployés:

output: {
  path: 'build',
  publicPath: "/vensa/",
  filename: 'bundle.js'
},
1
Brandon

Vous pouvez également utiliser une variable d’environnement pour ajuster manuellement tous vos liens.

const ENV = process.env.NODE_ENV || 'local'; //development
const config = {
    publicPath: ENV !== 'production' ? '/' : '/dev/'
};
plugins: ([
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(ENV),
            'process.env.config': JSON.stringify(config)
        })
})

Puis un de vos itinéraires:

<Route path={process.env.config.publicPath + "account/"} component={Account} />

Puis vos liens:

<Link class="panel-close" href={process.env.config.publicPath + "account/"} >Account</Link>

Cela a bien fonctionné pour moi. Surtout que j'utilise preact, dont le routeur preact ne supporte pas vraiment le nom de base pour le moment.

<Router history={browserHistory} basename={'foobar'}>
  <Route path="/" component={App} />
</Router>
1
lastlink

Dans ma situation, je devais prendre en charge un scénario dans lequel il pourrait y avoir 0 à plusieurs sous-dossiers avec des noms inconnus et la production utilise uniquement des fichiers statiques.

Dans mon App.js, j'ai défini cette fonction simple:

const getBasename = path => path.substr(0, path.lastIndexOf('/'));

Ce que j'utilise pour définir le nom de base:

<Router basename={getBasename(window.location.pathname)}>

Cela fonctionne avec aucun sous-dossier ainsi que plusieurs sous-dossiers et il peut également gérer les rechargements.

0
Ragnar