webpack-dev-server解決單頁面應用路由問題

目前比較主流的框架如Vue、React等,都是單頁面應用的框架。一般我們在使用它們的時候,會使用官方腳手架來創建項目,所以我們不必關心單頁面應用路由是如何實現的,因爲腳手架中已經幫我們做好了配置。在具體項目開發中,我們只需要做相應的路由配置即可。

那麼在實際項目中,手動搭建項目的前提下,我們需要如何解決單頁面應用的路由問題呢???

看個?:
目錄結構:

|--demo
	|--src
		|--index.html
		|--index.js
		|--home.js
		|--list.js
	|--node_modules
	|--.babelrc
	|--package-lock.json
	|--package.json
	|--webpack.config.js

webpack.config.js中的配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8081,
    hot: true,
    hotOnly: true
  },
  module: { 
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      exclude: /node_modules/
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

.babelrc配置:

{
  "presets": [
    [
      "@babel/preset-env", {
        "targets": {
          "chrome": "67"
        },
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ]
}

package.json中scripts配置:

"scripts": {
    "start": "webpack-dev-server"
}

src/index.js:

import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom'; // 引入路由模塊
import ReactDom from 'react-dom';
import Home from './home.js';
import List from './list.js';

// 這裏設置的路由,根據用戶的請求,來決定展示什麼
class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <Route path='/' exact component={ Home } />
          <Route path='/list' component={ List } />
        </div>
      </BrowserRouter> 
    )
  }
} 

ReactDom.render(<App />, document.getElementById('root'));

期望效果:

  • 當用戶訪問根路徑時,會訪問home組件的內容
  • 當用戶訪問/list路徑時,會訪問list組件的內容

src/home.js:

import React, { Component } from 'react';

class Home extends Component { 
  render() {
    return <div>HomePage</div>
  }
} 

export default Home;

src/list.js:

import React, { Component } from 'react';

class List extends Component {
  render() {
    return <div>ListPage</div>
  }
} 

export default List;

注: 記得通過npm包管理工具一一安裝上方所有配置項中的依賴、插件以及第三方庫。

執行打包:

npm run start

喚起瀏覽器localhost:8081服務:

當訪問"/list"路由時,我們期望出現ListPage的內容,但是實際情況如下:

注: 當我們去訪問localhost:8081/list這個地址的時候,webpackDevServer會默認爲你要訪問服務器上的一個list頁面。但我們的項目中只有一個index.html頁面,並不存在list頁面。所以它會提示你:Cannot GET /list (頁面不存在)

我們可以使用webpackDevServer中的 historyApiFallback 配置來解決此問題:

devServer: {
    contentBase: './dist',
    open: true,
    port: 8081,
    hot: true,
    hotOnly: true,
    historyApiFallback: true // 在使用單頁面應用的時候,需要設置此參數,代表如果訪問除根路徑以外的地址,最終都會轉向去請求根路徑。
},
  • historyApiFallback: true 代表在使用單頁面應用的時候,需要設置此參數,代表如果訪問除根路徑以外的地址,最終都會轉向去請求根路徑。

此時再執行打包:

npm  run  start

瀏覽器顯示正常:

打開控制檯網絡項:

從 “/list” 路由請求的響應信息我們可以看出,當訪問localhost:8081/list地址時,最終訪問的仍然是index.html頁面。到此,單頁面應用路由問題已完美解決。
所以,當我們在使用單頁面應用時,記得一定要在devServer中配置historyApiFallback: true配置項。

historyApiFallback 的詳細配置

historyApiFallback: {
      rewrites: [
        { from: /abc.html/, to: '/index.html' }
      ]
}
  • rewrites 中的配置代表:當我訪問locahost:8081/abc.html時,devServer會自動幫我們轉向訪問index.html頁面。
    • from 指訪問的地址
    • to 指devServer最終幫我們轉向的地址

所以上面例子中的 historyApiFallback:true 也就等價於:

historyApiFallback: {
      rewrites: [
        { 
        	from: /\.*/,  // 訪問任何地址
        	to: '/index.html'  // 都轉向index.html頁面(根路徑頁面)
        }
      ]
}

一般的項目中,當我們做單頁面應用,配置單頁面路由時,設置 historyApiFallback:true;即可解決。

注: historyApiFallback只是在我們的開發環境中(本地)有效,一旦代碼上線,就會再次出現訪問頁面找不到的問題。這時就需要後端小夥伴配合,仿照webpack-dev-server的配置,在nginx或apache對應的服務器上做它的一些配置,再進行訪問。??

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章