วิธีอนุญาตให้ webpack-dev-server อนุญาตจุดเข้าจาก react-router


117

ฉันกำลังสร้างแอปที่ใช้ webpack-dev-server ในการพัฒนาควบคู่ไปกับ react-router

ดูเหมือนว่า webpack-dev-server ถูกสร้างขึ้นจากสมมติฐานที่ว่าคุณจะมีจุดเข้าสาธารณะในที่เดียว (เช่น "/") ในขณะที่ react-router อนุญาตให้มีจุดเข้าได้ไม่ จำกัด จำนวน

ฉันต้องการประโยชน์ของ webpack-dev-server โดยเฉพาะอย่างยิ่งคุณสมบัติการรีโหลดใหม่ที่ยอดเยี่ยมสำหรับการทำงาน แต่ฉันยังต้องการโหลดเส้นทางที่ตั้งไว้ใน react-router

เราจะนำมันไปใช้งานร่วมกันได้อย่างไร? คุณสามารถเรียกใช้เซิร์ฟเวอร์ด่วนที่ด้านหน้าของ webpack-dev-server เพื่ออนุญาตสิ่งนี้ได้หรือไม่?


ฉันมีบางอย่างที่แฮ็คมากที่นี่ แต่มันบอบบางและอนุญาตให้จับคู่เส้นทางง่ายๆเท่านั้น: github.com/natew/react-base (ดู make-webpack-config) และ (app / route.js)
Nathan Wienert

คุณจัดการเพื่อแก้ปัญหานี้นาธานหรือไม่? ถ้าเป็นอย่างไร โปรดลองตอบคำถามของฉันที่นี่stackoverflow.com/questions/31091702/… . ขอบคุณ..!
SudoPlz

คำตอบ:


69

ฉันตั้งค่าพร็อกซีเพื่อให้บรรลุสิ่งนี้:

คุณมีเว็บเซิร์ฟเวอร์ Express ปกติที่ให้บริการ index.html บนเส้นทางใด ๆ ยกเว้นในกรณีที่เป็นเส้นทางสินทรัพย์ หากเป็นเนื้อหาคำขอจะได้รับพร็อกซีไปยัง web-dev-server

จุดเข้าใช้งานปฏิกิริยาร้อนของคุณจะยังคงชี้ไปที่เซิร์ฟเวอร์ webpack dev โดยตรงดังนั้นการรีโหลดแบบร้อนจึงยังคงทำงาน

สมมติว่าคุณเรียกใช้ webpack-dev-server บน 8081 และพร็อกซีของคุณที่ 8080 ไฟล์ server.js ของคุณจะมีลักษณะดังนี้:

"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);

ตอนนี้สร้างจุดเข้าของคุณในการกำหนดค่า webpack ดังนี้:

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

สังเกตการโทรโดยตรงไปที่ 8081 สำหรับ hotreload

ตรวจสอบให้แน่ใจว่าคุณได้ส่ง url ที่สมบูรณ์ไปยังoutput.publicPathตัวเลือก:

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

1
นี่มันสุดยอดมาก ฉันมาถึงการตั้งค่านี้ก่อนหน้านี้ไม่นานและกำลังจะโพสต์คำตอบ แต่ฉันคิดว่าคุณทำได้ดีกว่า
Nathan Wienert

1
คำถามหนึ่งข้อไม่เกี่ยวข้องดังนั้นฉันจึงสามารถเปิดคำถามใหม่ได้หากจำเป็น แต่ฉันสังเกตเห็นว่าตอนนี้เอาต์พุตคอนโซลจากเซิร์ฟเวอร์ webpack dev ไม่ได้สตรีม ก่อนหน้านี้คุณสามารถดูคอมไพล์และดูว่าเปอร์เซ็นต์เพิ่มขึ้นตอนนี้บล็อกเอาต์พุตหลังจากคอมไพล์แล้ว
Nathan Wienert

ทำได้ดีมาก นี่คือวิธีที่ควรทำ ฉันได้เพิ่มหมายเหตุเกี่ยวกับoutput.publicPathตัวเลือกซึ่งควรเป็น url แบบสัมบูรณ์ด้วย
Tobias K.

5
มันจะง่ายเพียงแค่ใช้ในตัวพร็อกซี่ webpackแทน ดังนั้นคุณจะไม่เข้าไปยุ่งในเซิร์ฟเวอร์เองคุณออกจากเซิร์ฟเวอร์บริสุทธิ์ แต่คุณทำเพียงเล็กน้อย (3-5 บรรทัด) นอกเหนือจากการกำหนดค่า webpack ขอบคุณที่คุณแก้ไขเฉพาะสคริปต์ dev เพื่อวัตถุประสงค์ในการพัฒนาและปล่อยให้รหัสการผลิต (server.js) อยู่ในความสงบ (ไม่เหมือนกับในเวอร์ชันของคุณ) และ imo เป็นวิธีที่เหมาะสม
jalooc

3
คำตอบนี้ยังคงถูกต้องแม้ว่าจะล้าสมัยไปหน่อย historyApiFallbackวิธีการตรงไปตรงมาเพิ่มเติมมีอยู่ตอนนี้มองหา
Eugene Kulabuhov

102

คุณควรตั้งค่าhistoryApiFallbackของWebpackDevServerจริงสำหรับการทำงาน นี่คือตัวอย่างเล็ก ๆ (ปรับแต่งให้เหมาะกับวัตถุประสงค์ของคุณ):

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);
});

คุณจะพลาดแถบสถานะที่ด้านบนของ index.html ของคุณ แต่มันใช้งานได้ดี :)
swennemen

7
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ จากเอกสารเซิร์ฟเวอร์ webpack dev: "หากคุณใช้ API ประวัติ HTML5 คุณอาจต้องให้บริการ index.html แทนการตอบกลับ 404 รายการซึ่งทำได้โดยการตั้งค่า historyApiFallback: true"หากฉันเข้าใจคำถามอย่างถูกต้องสิ่งนี้จะช่วยแก้ปัญหาได้ ปัญหา.
Sebastian

ง่ายมาก ... ขอบคุณ!
smnbbrv

1
@smnbbrv ไม่มีพร็อบ. มันจริงใช้เชื่อมต่อประวัติศาสตร์-API-สำรองtrueใต้และคุณสามารถผ่านวัตถุที่มีตัวเลือกที่เฉพาะเจาะจงมิดเดิลแวร์ถ้าคุณต้องการแทนเพียง
Juho Vepsäläinen

1
หรือถ้าคุณใช้ cliwebpack-dev-server --history-api-fallback
Levi

27

สำหรับใครที่ยังคงมองหาคำตอบนี้อยู่ ฉันรวบรวมพร็อกซีบายพาสอย่างง่ายซึ่งทำได้โดยไม่ยุ่งยากมากนักและ config จะเข้าสู่ webpack.config.js

ฉันแน่ใจว่ามีวิธีที่สวยงามกว่านี้ในการทดสอบเนื้อหาท้องถิ่นโดยใช้ regex แต่วิธีนี้ใช้ได้กับความต้องการของฉัน

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';
        }
      }
    }
  }
} 

ทำงานได้ดีสำหรับฉัน

ทำงานได้ดี! .. ขอบคุณ!
Dhrumil Bhankhar

นี่เป็นเพียงคำตอบที่สมบูรณ์แบบรวดเร็วและง่ายดาย
โดมิโน

12

หากคุณใช้ webpack-dev-server โดยใช้ CLI คุณสามารถกำหนดค่าผ่าน webpack.config.js ผ่านวัตถุ devServer:

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

สิ่งนี้จะเปลี่ยนเส้นทางไปที่ index.html ทุกครั้งที่พบ 404

หมายเหตุ: หากคุณใช้ publicPath คุณจะต้องส่งต่อไปยัง devServer ด้วย:

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

คุณสามารถตรวจสอบได้ว่าทุกอย่างได้รับการตั้งค่าอย่างถูกต้องโดยดูที่สองสามบรรทัดแรกของเอาต์พุต (ส่วนที่มี "404s will fallback to: path ")

ใส่คำอธิบายภาพที่นี่


11

สำหรับคำตอบล่าสุด webpack เวอร์ชันปัจจุบัน (4.1.1) คุณสามารถตั้งค่าได้ใน webpack.config.js ของคุณเช่น:

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
    }
  };

ส่วนที่สำคัญคือhistoryApiFallback: true. ไม่จำเป็นต้องเรียกใช้เซิร์ฟเวอร์ที่กำหนดเองเพียงแค่ใช้ cli:

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

2

ฉันต้องการเพิ่มคำตอบสำหรับกรณีนี้เมื่อคุณเรียกใช้แอป isomorphic (เช่นการแสดงผล React คอมโพเนนต์ฝั่งเซิร์ฟเวอร์)

ในกรณีนี้คุณอาจต้องการโหลดเซิร์ฟเวอร์ซ้ำโดยอัตโนมัติเมื่อคุณเปลี่ยนส่วนประกอบ React ของคุณ คุณทำสิ่งนี้กับpipingแพ็คเกจ ทั้งหมดที่คุณต้องทำคือการติดตั้งและเพิ่มrequire("piping")({hook: true})ที่ไหนสักแห่งในการเริ่มต้นของคุณserver.js แค่นั้นแหละ. เซิร์ฟเวอร์จะรีสตาร์ทหลังจากที่คุณเปลี่ยนส่วนประกอบใด ๆ ที่ใช้งาน

สิ่งนี้ทำให้เกิดปัญหาขึ้นอีก - หากคุณเรียกใช้เซิร์ฟเวอร์ webpack จากกระบวนการเดียวกันกับเซิร์ฟเวอร์ด่วนของคุณ (ตามคำตอบที่ยอมรับด้านบน) เซิร์ฟเวอร์ webpack จะรีสตาร์ทและจะคอมไพล์ชุดของคุณใหม่ทุกครั้ง เพื่อหลีกเลี่ยงปัญหานี้คุณควรเรียกใช้เซิร์ฟเวอร์หลักและเซิร์ฟเวอร์ Webpack ในกระบวนการที่แตกต่างกันเพื่อให้ไพพ์รีสตาร์ทเฉพาะเซิร์ฟเวอร์ด่วนของคุณและจะไม่แตะ webpack คุณสามารถทำได้ด้วยconcurrentlyแพ็คเกจ คุณสามารถค้นหาตัวอย่างของในนี้ตอบสนอง-isomorphic-STARTERKIT ในpackage.jsonเขามี:

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

ซึ่งทำงานทั้งสองเซิร์ฟเวอร์พร้อมกัน แต่อยู่ในกระบวนการแยกกัน


นี่หมายความว่ามีการดูไฟล์บางไฟล์สองครั้งหรือไม่? เช่นไฟล์ isomorphic / universal ที่ใช้ร่วมกัน?
David Sinclair



-1

สิ่งนี้ใช้ได้ผลสำหรับฉัน: เพียงแค่เพิ่มไฟล์มิดเดิลแวร์ของ webpack ก่อนและapp.get('*'...ตัวแก้ไข index.html ในภายหลัง

ดังนั้นด่วนจะตรวจสอบก่อนว่าคำขอตรงกับเส้นทางใดเส้นทางหนึ่งที่ webpack ให้มา (เช่น: /dist/bundle.jsหรือ/__webpack_hmr_) และถ้าไม่เช่นนั้นระบบจะย้ายไปที่index.htmlด้วย*ตัวแก้ไข

เช่น:

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)
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.