简体   繁体   English

使用 webpack dev server 和 rails server 进行 webpack 热重载

[英]Webpack hot reload using webpack dev server and rails server

My current application is set up using Ruby on Rails and React/Typescript.我当前的应用程序是使用 Ruby on Rails 和 React/Typescript 设置的。 I am trying to set up hot reloading.我正在尝试设置热重载。

Here is the current folder structure这是当前的文件夹结构

Project Root
  - app => all the rails code
  - frontend => all the react code
  - webpack => list of configuration files, like development.js and production.js

This project isn't using react_on_rails or webpacker .这个项目没有使用react_on_railswebpacker The frontend code is kept separate from the backend code.前端代码与后端代码分开保存。 The Rails backend serves up an html Rails 后端提供一个 html

<div id='root' />

and the react code will run off of that.并且反应代码将运行。

This is the command I tried to run to get hot reloading to work这是我尝试运行以使热重新加载工作的命令

node_modules/.bin/webpack-dev-server --config=./webpack/development.js  --hotOnly --entry=../frontend/Entry.tsx --allowedHosts=localhost:3000

However, not only is hot reloading not working, the changes I made are not showing up in the browser as well.但是,热重载不仅不起作用,而且我所做的更改也没有显示在浏览器中。 Everything looks like in the terminal.一切看起来都像在终端中。

My issue here is I technically have two servers running at the same time.我的问题是我在技术上有两台服务器同时运行。

localhost:3000 => Rails server
localhost:8080 => Webpack dev server. 

If I change webpack server to point to 3000 as well, the rails app will not work properly.如果我将 webpack 服务器也更改为指向 3000,rails 应用程序将无法正常工作。

Is there a way where I can get hot reloading to work using this setup?有没有办法可以使用此设置进行热重新加载?

here are the webpack version这是 webpack 版本

"webpack": "^4.20.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.7.1" 

webpack.development.config.js webpack.development.config.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');

module.exports = {
  context: __dirname,
  entry: '../frontend/Entry.tsx',
  devtool: 'source-maps',
  resolve: {
    extensions: ['*', '.js', '.jsx', '.ts', '.tsx'],
    modules: [
      'node_modules',
      path.resolve(__dirname, '../frontend'),
      path.resolve(__dirname, '../node_modules')
    ]
  },
  output: {
    path: path.join(__dirname, `../public/javascripts/`),
    publicPath: `/javascripts/`,
    filename: '[name]-[hash].js'
  },
  module: {
    rules: [
      {
        test: /\.(t|j)sx?$/,
        loader: 'ts-loader',
        options: {
          // disable type checker - we will use it in fork plugin
          transpileOnly: true
        }
      },
      {
        enforce: 'pre',
        test: /\.(t|j)sx?$/,
        loader: 'source-map-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name]-[hash].[ext]',
              outputPath: 'images/'
            }
          },
          {
            loader: 'image-webpack-loader',
            options: {
              pngquant: {
                quality: '40',
                speed: 4
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development')
      }
    }),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, '..', 'application.html'),
      filename: path.join(__dirname, '..', 'app', 'views', 'layouts', '_javascript.html.erb')
    }),
    // runs typescript type checker on a separate process.
    new ForkTsCheckerWebpackPlugin({
      checkSyntacticErrors: true,
      tsconfig: '../tsconfig.json'
    }),
    new CaseSensitivePathsPlugin()
  ],
  optimization: {
    splitChunks: { chunks: 'all' }
  }
};

Since you are setting up webpack dev server the first time, the problem is two fold,由于您是第一次设置 webpack 开发服务器,问题是双重的,

  1. Setup webpack dev server设置 webpack 开发服务器
  2. Configure hot reload配置热重载

Setting up webpack dev server设置 webpack 开发服务器

I presume your app is the api server.我认为您的应用程序是 api 服务器。 Similarly webpack-dev-server too is a http server.同样 webpack-dev-server 也是一个 http 服务器。 Its just a wrapper around expressjs infact.事实上,它只是对 expressjs 的一个包装。

while using webpack dev server during development, the bundles are served by webpack dev server, and all xhr requests are made to this dev server.在开发过程中使用 webpack dev server 时,bundle 由 webpack dev server 提供,所有 xhr 请求都发送到这个 dev server。 In order to route these requests to your app server, you need to add proxy rules to your webpack config.为了将这些请求路由到您的应用服务器,您需要将代理规则添加到您的 webpack 配置中。

On a high level the flow would look as follows.在较高级别上,流程如下所示。

browser ---(xhr requests)-----> webpack-dev-server -----(proxy api requests)--->app server


In order to add a proxy rule to route all api request to your rails server, your api routes should be prepended with /api , eg, /api/customers so that all request matching /api are forwarded to the rails server为了添加代理规则以将所有 api 请求路由到您的 rails 服务器,您的 api 路由应该预先加上/api ,例如/api/customers以便所有与/api匹配的请求都转发到 rails 服务器

A sample config to support the above flow would be something as follows in your webpack config file支持上述流程的示例配置在您的 webpack 配置文件中如下所示

module.exports = {
  // ...your other configs
  devServer: {
    contentBase: path.join(__dirname, 'public/'),
    port: 8080,
    publicPath: 'http://localhost:8080/', // Path of your dev server
    historyApiFallback: true, // add this if you are not using browser router
    proxy: {
      '/api': { // string to look for proxying requests to api
        target: 'http://localhost:3000', // Path of your rails api server
      },
    },
  },
  // ...your other configs
}

Setting up Hot reload设置热重载

In order to setup hot reload, I would recommend to use Dan Abramov's react-hot-loader as its less buggy in hmr patching.为了设置热重载,我建议使用 Dan Abramov 的react-hot-loader,因为它在 hmr 补丁中的错误较少。

Setting up hmr is easy设置 hmr 很容易

  1. Add the dependency yarn add react-hot-loader添加依赖yarn add react-hot-loader
  2. Add babel plugin in your .babelrc在 .babelrc 中添加 babel 插件

    { "plugins": ["react-hot-loader/babel"] }
  3. Mark your root component as hot exported将您的根组件标记为热导出

    import { hot } from 'react-hot-loader/root'; // this should be imported before react and react-dom const App = () => <div>Hello World!</div>; export default hot(App);

Note: Its safe to add react-hot-loader in your dependencies, because in your production build.注意:在您的依赖项中添加react-hot-loader是安全的,因为在您的生产版本中。 Hot reload package will be stripped out.热重载包将被剥离。

To start the webpack server in hot mode, you can add a script like below in your package.json .要以热模式启动 webpack 服务器,您可以在package.json添加如下脚本。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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