Компонент React не отображает

#javascript #reactjs #webpack

#javascript #reactjs #webpack

Вопрос:

У меня есть приложение React microfrontend. До сих пор я собрал два вспомогательных приложения, которые отображаются через container/ проект. Изолированно, на localhost: 8083 я могу видеть рендеринг вспомогательного приложения просто отлично, но, в отличие от других вспомогательных приложений, когда мне нужно просмотреть его через localhost: 8080 / dashboard, я не получаю ничего, кроме белого экрана и, что еще хуже, никакой ошибки в терминале, никакой ошибки в консоли, никакой ошибки всетевые запросы.

Это мой webpack.dev.js файл в container/ :

 const { merge } = require("webpack-merge");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const commonConfig = require("./webpack.common");
const packageJson = require("../package.json");

const devConfig = {
  mode: "development",
  output: {
    publicPath: "http://localhost:8080/",
  },
  devServer: {
    port: 8080,
    historyApiFallback: true,
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "container",
      remotes: {
        marketing: "marketing@http://localhost:8081/remoteEntry.js",
        auth: "auth@http://localhost:8082/remoteEntry.js",
        dashboard: "dashboard@http://localhost:8083/remoteEntry.js",
      },
      shared: packageJson.dependencies,
    }),
  ],
};

module.exports = merge(commonConfig, devConfig);
 

Я неоднократно смотрел на это, не вижу в этом ничего плохого.

Это webpack.common.js файл, который у меня есть в этой container/ папке:

 const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react', '@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime']
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
  ]
}
 

Я посмотрел на это и не вижу в этом ничего плохого.

Вот мой components/DashboardApp.js файл внутри container/ :

 import { mount } from "dashboard/DashboardApp";
import React, { useRef, useEffect } from "react";
import { useHistory } from "react-router-dom";

export default ({ onSignIn }) => {
  const ref = useRef(null);
  const history = useHistory();

  useEffect(() => {
    const { onParentNavigate } = mount(ref.current, {
      initialPath: history.location.pathname,
      onNavigate: ({ pathname: nextPathname }) => {
        const { pathname } = history.location;

        if (pathname !== nextPathname) {
          history.push(nextPathname);
        }
      },
      onSignIn,
    });

    history.listen(onParentNavigate);
  }, []);

  return <div ref={ref} />;
};
 

Мой container/src/App.js файл:

 import React, { lazy, Suspense, useState } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
  StylesProvider,
  createGenerateClassName,
} from "@material-ui/core/styles";

import Progress from "./components/Progress";
import Header from "./components/Header";

const MarketingLazy = lazy(() => import("./components/MarketingApp"));
const AuthLazy = lazy(() => import("./components/AuthApp"));
const DashboardLazy = lazy(() => import("./components/DashboardApp"));

const generateClassName = createGenerateClassName({
  productionPrefix: "co",
});

export default () => {
  const [isSignedIn, setIsSignedIn] = useState(false);

  return (
    <BrowserRouter>
      <StylesProvider generateClassName={generateClassName}>
        <div>
          <Header
            onSignOut={() => setIsSignedIn(false)}
            isSignedIn={isSignedIn}
          />
          <Suspense fallback={<Progress />}>
            <Switch>
              <Route path='/auth'>
                <AuthLazy onSignIn={() => setIsSignedIn(true)} />
              </Route>
              <Route path='/dashboard' component={DashboardLazy} />
              <Route path='/' component={MarketingLazy} />
            </Switch>
          </Suspense>
        </div>
      </StylesProvider>
    </BrowserRouter>
  );
};
 

Может ли кто-нибудь увидеть что-нибудь, что я, возможно, пропустил? Почему этот компонент не будет отображаться через container/ , тогда как другие вспомогательные приложения, созданные точно так же, могут.

Комментарии:

1. действителен ли ваш URL-адрес удаленного входа? маркетинг: «marketing@localhost:8081/remoteEntry.js »


2. Взгляните на этот URL blog.bitsrc.io /… , похоже, база контента отсутствует

3. @Sam, я только что попробовал contentBase, и это не отображало дополнительное приложение, выглядит так же, как и раньше.

4. @Sam, да, это marketing: "marketing@http://localhost:8081/remoteEntry.js", действительно, у меня нет никаких проблем с ним или auth с ним.

5. Рад, что вы можете заставить его работать, как вы пока находите объединение модулей. у вас есть какие-либо другие проблемы?. Мы планируем использовать в нашем приложении, просто хотим знать, как это пока?

Ответ №1:

Когда приложение начинает усложняться, речь идет о мельчайших деталях. В то время как в моем container/src/App.js файле был a path="/dashboard" , в моем dashboard/src/App.js файле его не было, он выглядел так:

 import React from "react";
import { Switch, Route, Router } from "react-router-dom";
import {
  StylesProvider,
  createGenerateClassName,
} from "@material-ui/core/styles";
import Dashboard from "./components/Dashboard";

const generateClassName = createGenerateClassName({
  productionPrefix: "da",
});

export default ({ history }) => {
  return (
    <div>
      <StylesProvider generateClassName={generateClassName}>
        <Router history={history}>
          <Switch>
            <Route exact path='/' component={Dashboard} />
          </Switch>
        </Router>
      </StylesProvider>
    </div>
  );
};
 

Однажды я изменил его на этот:

 import React from "react";
import { Switch, Route, Router } from "react-router-dom";
import {
  StylesProvider,
  createGenerateClassName,
} from "@material-ui/core/styles";
import Dashboard from "./components/Dashboard";

const generateClassName = createGenerateClassName({
  productionPrefix: "da",
});

export default ({ history }) => {
  return (
    <div>
      <StylesProvider generateClassName={generateClassName}>
        <Router history={history}>
          <Switch>
            <Route exact path='/dashboard' component={Dashboard} />
          </Switch>
        </Router>
      </StylesProvider>
    </div>
  );
};
 

Теперь он отображается внутри родительского контейнера.

Ответ №2:

Вам не хватает contentBase.

 devServer: {
    contentBase: path.join(__dirname, "dist"),
    port: 3002,
  },
  output: {
    publicPath: "http://localhost:3002/",
  },