Webpack-dev-server'ın react-router'dan giriş noktalarına izin vermesine nasıl izin verilir


117

React-router ile birlikte geliştirme aşamasında webpack-dev-server kullanan bir uygulama oluşturuyorum.

Görünüşe göre webpack-dev-server, tek bir yerde (yani "/") genel bir giriş noktasına sahip olacağınız varsayımı etrafında inşa edilmiştir, oysa react-router sınırsız sayıda giriş noktası sağlar.

Webpack-dev-server'ın faydalarını, özellikle üretkenlik için harika olan yeniden yükleme özelliğini istiyorum, ancak yine de react-router'da ayarlanan yolları yükleyebilmek istiyorum.

Birlikte çalışacak şekilde nasıl uygulanabilir? Webpack-dev-server önünde buna izin verecek şekilde bir ekspres sunucu çalıştırabilir misiniz?


Burada bir şeyin son derece karmaşık bir versiyonuna sahibim, ancak kırılgan ve yalnızca basit rotaların eşleşmesine izin veriyor: github.com/natew/react-base (bkz. Make-webpack-config) ve (app / route.js)
Nathan Wienert

Bu sorunu çözmeyi başardın mı Nathan? Öyleyse nasıl? Lütfen sorumu burada stackoverflow.com/questions/31091702/… yanıtlamaya çalışın . Teşekkür ederim..!
SudoPlz

Yanıtlar:


69

Bunu başarmak için bir proxy kurdum:

Bir varlık yolu dışında herhangi bir rotada index.html'yi sunan normal bir ekspres web sunucunuz var. bir varlık ise, istek web-dev-server'a proxy ile bağlanır

Tepki sıcak giriş noktalarınız doğrudan web paketi geliştirici sunucusunu göstermeye devam eder, bu nedenle yeniden yükleme hala çalışır.

Webpack-dev-server'ı 8081'de ve proxy'nizi 8080'de çalıştırdığınızı varsayalım. Server.js dosyanız şöyle görünecektir:

"use strict";
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./make-webpack-config')('dev');

var express = require('express');
var proxy = require('proxy-middleware');
var url = require('url');

## --------your proxy----------------------
var app = express();
## proxy the request for static assets
app.use('/assets', proxy(url.parse('http://localhost:8081/assets')));

app.get('/*', function(req, res) {
    res.sendFile(__dirname + '/index.html');
});


# -----your-webpack-dev-server------------------
var server = new WebpackDevServer(webpack(config), {
    contentBase: __dirname,
    hot: true,
    quiet: false,
    noInfo: false,
    publicPath: "/assets/",

    stats: { colors: true }
});

## run the two servers
server.listen(8081, "localhost", function() {});
app.listen(8080);

şimdi web paketi yapılandırmasında giriş noktalarınızı şu şekilde yapın:

 entry: [
     './src/main.js',
     'webpack/hot/dev-server',
     'webpack-dev-server/client?http://localhost:8081'
 ]

sıcak yeniden yükleme için 8081'e doğrudan çağrıya dikkat edin

ayrıca output.publicPathseçeneğe mutlak bir url ilettiğinizden emin olun :

 output: {
     publicPath: "http://localhost:8081/assets/",
     // ...
 }

1
Hey, bu harika. Aslında bu düzene bundan kısa bir süre önce ulaştım ve bir cevap gönderecektim ama bence daha iyi bir iş çıkardın.
Nathan Wienert

1
Bir soru, biraz ilgisiz, böylece gerekirse yeni bir soru açabilirim, ancak şimdi web paketi dev sunucusundan konsol çıktısının akışa alınmadığını fark ettim. Önceden, derlemesini izleyebilir ve yüzdelerin yükseldiğini görebilirdiniz, şimdi sadece derlemeden sonra çıktıları bloke ediyor.
Nathan Wienert

İyi iş çıkardın. Bu tam olarak nasıl yapılmalı. output.publicPathSeçenek hakkında da mutlak bir url olması gereken bir not ekledim .
Tobias K.

5
Bunun yerine yerleşik bir web paketi proxy'si kullanmak daha kolay olurdu . Böylece sunucunun kendisine müdahale etmezsiniz, sunucuyu saf bırakırsınız . Bunun yerine, webpack yapılandırmasına biraz (3-5 satır) ekleme yaparsınız. Bunun sayesinde, yalnızca geliştirici komut dosyalarını geliştirme amaçlı olarak değiştirirsiniz ve üretim kodunu (server.js) rahat bırakırsınız (sürümünüzün aksine) ve imo'yu kullanmanın doğru yolu budur.
jalooc

3
Bu cevap biraz tarihli olmasına rağmen hala doğrudur. Şimdi daha basit yollar var, arayın historyApiFallback.
Eugene Kulabuhov

102

Sen belirlesin historyApiFallbackait WebpackDevServerçalışmalarına bunun için gerçek olarak. İşte küçük bir örnek (amaçlarınıza uyacak şekilde ince ayar yapın):

var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');

var config = require('./webpack.config');


var port = 4000;
var ip = '0.0.0.0';
new WebpackDevServer(webpack(config), {
    publicPath: config.output.publicPath,
    historyApiFallback: true,
}).listen(port, ip, function (err) {
    if(err) {
        return console.log(err);
    }

    console.log('Listening at ' + ip + ':' + port);
});


7
Kabul edilen cevap bu olmalıdır. Web paketi geliştirici sunucusu belgelerinden: "HTML5 geçmiş API'sini kullanıyorsanız büyük olasılıkla 404 yanıtı yerine index.html dosyanızı sunmanız gerekir; bunu historyApiFallback: true ayarlayarak yapabilirsiniz" Soruyu doğru anlarsam bu çözülür sorun.
Sebastian

çok basit ... Teşekkür ederim!
smnbbrv

1
@smnbbrv Sorun yok. Aslında altında bağlantı-geçmişi-api-fallback kullanır ve bir nesneyi sadece yerine ara katman yazılımına özgü seçeneklerle geçirebilirsiniz true.
Juho Vepsäläinen

1
VEYA klibi kullanıyorsanız,webpack-dev-server --history-api-fallback
Levi

27

Hala bu cevabı arayan başka biri için. Bunu çok fazla güçlük çekmeden gerçekleştiren basit bir proxy atlama oluşturdum ve yapılandırma webpack.config.js'ye gider

Normal ifadeyi kullanarak yerel içeriği test etmenin çok daha zarif yolları olduğundan eminim, ancak bu benim ihtiyaçlarım için çalışıyor.

devServer: {
  proxy: { 
    '/**': {  //catch all requests
      target: '/index.html',  //default target
      secure: false,
      bypass: function(req, res, opt){
        //your custom code to check for any exceptions
        //console.log('bypass check', {req: req, res:res, opt: opt});
        if(req.path.indexOf('/img/') !== -1 || req.path.indexOf('/public/') !== -1){
          return '/'
        }

        if (req.headers.accept.indexOf('html') !== -1) {
          return '/index.html';
        }
      }
    }
  }
} 

Benim için iyi çalıştı
Nath

Güzel çalıştı! .. Teşekkürler!
Dhrumil Bhankhar

Bu sadece mükemmel bir cevap, hızlı ve kolay.
domino

12

CLI kullanarak webpack-dev-server çalıştırıyorsanız, bunu webpack.config.js aracılığıyla devServer nesnesini geçirerek yapılandırabilirsiniz:

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js"
  },
  devServer: {
    historyApiFallback: true
  }
}

Bu, 404 ile her karşılaşıldığında index.html'ye yeniden yönlendirecektir.

NOT: publicPath kullanıyorsanız, bunu devServer'a da iletmeniz gerekir:

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js",
    publicPath: "admin/dashboard"
  },
  devServer: {
    historyApiFallback: {
      index: "admin/dashboard"
    }
  }
}

Çıktının ilk birkaç satırına bakarak her şeyin doğru şekilde kurulduğunu doğrulayabilirsiniz ("404'lere sahip bölüm: yol " a geri dönecektir ).

görüntü açıklamasını buraya girin


11

Daha yeni bir yanıt için, webpack'in (4.1.1) güncel sürümü, bunu webpack.config.js'de şu şekilde ayarlayabilirsiniz:

const webpack = require('webpack');

module.exports = {
    entry: [
      'react-hot-loader/patch',
      './src/index.js'
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ['style-loader','css-loader']
            }
        ]
    },
    resolve: {
      extensions: ['*', '.js', '.jsx']  
    },
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: 'bundle.js'
    },
    plugins: [
      new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
      contentBase: './dist',
      hot: true,
      historyApiFallback: true
    }
  };

Önemli olan kısım historyApiFallback: true. Özel bir sunucu çalıştırmanıza gerek yok, sadece cli'yi kullanın:

"scripts": {
    "start": "webpack-dev-server --config ./webpack.config.js --mode development"
  },

2

Bir izomorfik uygulama çalıştırdığınızda (yani, React bileşeninin sunucu tarafında işlenmesi) durum için cevaba eklemek istiyorum.

Bu durumda, muhtemelen React bileşenlerinizden birini değiştirdiğinizde sunucuyu otomatik olarak yeniden yüklemek istersiniz. Bunu pipingpaketle yaparsınız . Tek yapmanız gereken onu kurmak ve server.js’nizinrequire("piping")({hook: true}) başında bir yere eklemek . Bu kadar. Sunucu, kullandığı herhangi bir bileşeni değiştirdikten sonra yeniden başlayacaktır.

Yine de bu başka bir sorun ortaya çıkarır - eğer web paketi sunucusunu ekspres sunucunuzla aynı işlemden çalıştırırsanız (yukarıdaki kabul edilen cevapta olduğu gibi), web paketi sunucusu da yeniden başlayacak ve her seferinde paketinizi yeniden derleyecektir. Bundan kaçınmak için, ana sunucunuzu ve web paketi sunucunuzu farklı işlemlerde çalıştırmalısınız, böylece borular yalnızca ekspres sunucunuzu yeniden başlatır ve web paketine dokunmaz. Bunu concurrentlypaket ile yapabilirsiniz . Bunun bir örneğini react-isomorphic-starterkit'te bulabilirsiniz . Gelen package.json o vardır:

"scripts": {
    ...
    "watch": "node ./node_modules/concurrently/src/main.js --kill-others 'npm run watch-client' 'npm run start'"
  },

Bu, her iki sunucuyu aynı anda ancak ayrı işlemlerde çalıştırır.


Bu, bazı dosyaların iki kez izlendiği anlamına mı geliyor? Paylaşılan izomorfik / evrensel dosyalar gibi mi?
David Sinclair

1

historyApiFallback rotaları içeren bir Boolean yerine bir nesne de olabilir.

historyApiFallback: navData && {
  rewrites: [
      { from: /route-1-regex/, to: 'route-1-example.html' }
  ]
}


-1

Bu benim için çalıştı: sadece önce web paketi ara yazılımlarını ekleyin ve app.get('*'... index.html çözümleyicisini ,

böylece isteği (gibi: WebPack tarafından sağlanan rotalardan birini eşleşirse ilk kontrol edecektir ekspres /dist/bundle.jsveya /__webpack_hmr_) ve değilse, o zaman hareket edecek index.htmlolan* resolverli.

yani:

app.use(require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
}))
app.use(require('webpack-hot-middleware')(compiler))
app.get('*', function(req, res) {
  sendSomeHtml(res)
})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.