You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地构建正常,GitHub Actions构建时Webpack模块解析失败

容器微前端GitHub Actions构建失败:模块找不到错误

将代码推送到GitHub后,GitHub Actions执行npm install和npm run build时出现以下错误:

ERROR in ./src/App.js ... Module not found: Error: Can't resolve './components/navbar/Progress' in '/home/runner/work///packages/container/src'


GitHub Actions错误信息

控制台日志核心提示:无法解析./components/navbar/Progress模块路径


webpack.common.js配置

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'],
          },
        },
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(scss)$/,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader' },
          { loader: 'sass-loader' },
        ]
      },
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
      {
        test: /\.(png|jpg|jpeg|gif|ico)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[path][name].[ext]?hash=[hash:20]',
              limit: 8192
            },
          },
        ],
      },
      {
        test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
        use: [{ loader: 'file-loader' }]
      },
      {
        test: /\.(ttf|eot|woff|woff2)$/,
        loader: 'file-loader',
        options: { name: 'fonts/[name].[ext]' },
      },
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
  ],

  resolve: {
    extensions: ['', '.js', '.jsx', '.scss', '.eot', '.ttf', '.svg', '.woff'],
    modules: ['node_modules', 'scripts', 'images', 'fonts'],
  },
};

webpack.prod.js配置

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

const domain = process.env.PRODUCTION_DOMAIN;

const prodConfig = {
  mode: 'production',
  output: {
    filename: '[name].[contenthash].js',
    publicPath: '/container/latest/',
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'container',
      filename: 'remoteEntry.js',
      remotes: {
        marketingMfe: `marketingMod@${domain}/marketing/latest/remoteEntry.js`,
        authMfe: `authMod@${domain}/auth/latest/remoteEntry.js`,
        companyMfe: `companyMod@${domain}/company/latest/remoteEntry.js`,
      },
      exposes: {
        './Functions': './src/functions/Functions',
        './Variables': './src/data-variables/Variables'
      },
      shared: {...packageJson.dependencies, ...packageJson.peerDependencies},
    }),
  ],
};

module.exports = merge(commonConfig, prodConfig);

容器微前端目录结构

| config
| public
| | index.html
| src
| | assets
| | components
| | | navbar
| | | ...some components
| | data-variables
| | | Variables.js
| | functions
| | | Functions.js
| | App.js
| | bootstrap.js
| | index.js

App.js核心代码

import React, { lazy, Suspense, useState, useEffect } from 'react';
import { Router, Route, Switch, Redirect } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import { createGlobalStyle } from 'styled-components';

import WebFont from 'webfontloader';

WebFont.load({
  google: { families: ['Barlow', 'Playfair Display', 'Overpass', 'Montserrat'] }
});

import Progress from './components/navbar/Progress';
import Header from './components/Header';

const MarketingLazy = lazy(() => import('./components/MarketingApp'));
const AuthLazy = lazy(() => import('./components/AuthApp'));
const CompaniesLazy = lazy(() => import('./components/CompanyApp'));

const history = createBrowserHistory();

const GlobalStyle = createGlobalStyle`
  body { height: 100%; min-height: 100vh; margin: 0; padding: 0; }
  html { height: 100%; }
`

export default function App() {
  const [isSignedIn, setIsSignedIn] = useState(false);
  useEffect(() => {
    if (isSignedIn) history.push('/companies/last')
  }, [isSignedIn]);

  return (
    <Router history={history}>
      <div>
        <GlobalStyle />
        <Header onSignOut={() => setIsSignedIn(false)} isSignedIn={isSignedIn} />
        <Suspense fallback={<Progress />} >
          <Switch>
            <Route path="/auth/*">
              <AuthLazy onSignIn={() => setIsSignedIn(true)} />
            </Route>
            <Route path="/companies/last">
              { !isSignedIn && <Redirect to="/" />}
              <CompaniesLazy />
            </Route>
            <Route path="/companies">
              { !isSignedIn && <Redirect to="/" />}
              <CompaniesLazy />
            </Route>
            <Route path="/user">
              { !isSignedIn && <Redirect to="/" />}
              <CompaniesLazy />
            </Route>
            <Route path="/" component={MarketingLazy} />
          </Switch>
        </Suspense>
      </div>
    </Router>
  );
};

解决步骤

  1. 检查文件路径与大小写:GitHub Actions运行在Linux环境,文件名严格区分大小写。确认本地src/components/navbar/下的Progress组件文件名(如Progress.js/Progress.jsx)与导入语句的大小写完全一致,且文件确实存在。
  2. 修复webpack扩展名配置:当前resolve.extensions中的空字符串''可能导致解析异常,建议移除,修改为:
    resolve: {
      extensions: ['.js', '.jsx', '.scss', '.eot', '.ttf', '.svg', '.woff'],
      modules: ['node_modules', 'scripts', 'images', 'fonts'],
    },
    
  3. 确认文件已提交到仓库:检查GitHub仓库中是否存在src/components/navbar/Progress相关文件,避免本地存在但未提交的情况。
  4. 同步目录结构:确保本地目录结构与仓库完全一致,无嵌套错误或文件位置变更未同步的问题。

内容的提问来源于stack exchange,提问作者melv3223

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 03:15:58