我怎样才能“引导”?当 webpack 输出类型为“library”时是否支持 webpack 模块联合?

发布于 2025-01-17 11:58:51 字数 3105 浏览 0 评论 0原文

我有一个带有webpack配置的WebPack“库”项目,看起来像这样:

module.exports = ({ mode }) => {
    const isProd = mode === 'production';
    return {
        mode,
        entry: './src/index.tsx',
        output: {
            library: 'MyLibraryComponents',
            path: path.resolve(__dirname, 'build'),
            filename: getOutputFileName(isProd),
        },
        devServer: { ... },
        optimization: { ... },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    loader: 'ts-loader',
                },
                {
                    test: /\.less$/i,
                    use: [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' },
                        {
                            loader: 'less-loader',
                        },
                    ],
                },
                {
                    test: /\.css$/i,
                    use: ['style-loader', 'css-loader'],
                },
            ],
        },
        resolve: {
            extensions: ['.ts', '.tsx', '.js'],
        },
        plugins: [
            new HtmlWebpackPlugin({
                inject: true,
                scriptLoading: 'blocking',
                template: resolveAppPath('public/index.html'),
            }),
        ],
    };
};

此WebPack构建创建一个名为“ mylibraryComponents”的全局变量,该变量的方法具有使用React> React> Reactdom.render()给定htmlelement的React React组件的方法。我的项目之所以以这种方式设置,是因为我正在旧版应用程序中工作,但是想在React中重新编写UI的某些部分。

这是库的输入文件的样子。条目文件在.ts中,但我在这里对其进行了一些简化:

// src/index.tsx

import ReactDOM from 'react-dom';

export Examples = {
   FooComponent: {
       async render(htmlElement, props) {
           const { default: Foo } = await import("./components/Foo");
           ReactDOM.render(<Foo {...props} />, htmlElement);
       }
   },
   BarComponent: {
       async render(htmlElement, props) {
           const { default: Bar } = await import("./components/Bar");
           ReactDOM.render(<Bar {...props} />, htmlElement);
       }
   }
};

当WebPack MAIN Bundle使用&lt; script src ='''''' &gt;,它在window上创建一个对象, mylibraryComponents。然后,我可以将React组件渲染到这样的旧应用程序中:mylibrarycomponents.examples.fooocomponent.render(...)

随着添加了更多组件,我有兴趣使用模块Federation使用模块联盟。作为一种独立部署组件并隔离依赖项等的手段。

但是,在所有模块联合项目示例中,我看到的示例有必要拥有一个“ bootstrap”文件并让您的WebPack输入文件执行此操作。然后,您的应用程序的“真实”输入文件应重命名为bootstrap.js

import("./bootstrap")

显然,这确保了项目的共享模块首先由浏览器加载或类似的东西。原因对我来说还不清楚100%。

我看到的问题是,我的项目的输入文件实际上具有我的WebPack库取决于的“导出”,而如果这是传统的React应用程序,则只会执行类似的操作:

import ReactDOM from "react-dom";
import App from "./App;

ReactDOM.render(<App />, document.getElementById("root"));

如果我将输入点文件更新为import('./ bootstrap'),然后在我在控制台中检查它时,我的库最终是一个空对象。

有没有一种方法可以编写“ Bootstrap”条目文件,以便我可以支持该项目中的模块联合会?

感谢您的帮助。

I have a webpack 'library' project with a webpack config that looks like this:

module.exports = ({ mode }) => {
    const isProd = mode === 'production';
    return {
        mode,
        entry: './src/index.tsx',
        output: {
            library: 'MyLibraryComponents',
            path: path.resolve(__dirname, 'build'),
            filename: getOutputFileName(isProd),
        },
        devServer: { ... },
        optimization: { ... },
        module: {
            rules: [
                {
                    test: /\.tsx?$/,
                    loader: 'ts-loader',
                },
                {
                    test: /\.less$/i,
                    use: [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' },
                        {
                            loader: 'less-loader',
                        },
                    ],
                },
                {
                    test: /\.css$/i,
                    use: ['style-loader', 'css-loader'],
                },
            ],
        },
        resolve: {
            extensions: ['.ts', '.tsx', '.js'],
        },
        plugins: [
            new HtmlWebpackPlugin({
                inject: true,
                scriptLoading: 'blocking',
                template: resolveAppPath('public/index.html'),
            }),
        ],
    };
};

This webpack build creates a global variable called "MyLibraryComponents", which has methods on it that render react components given an HTMLElement using ReactDOM.render(). My project is set up this way because I'm working in a legacy application, but want to re-write certain parts of the UI in react.

Here is what the entry file for the library looks like. The entry file is in .ts but I've simplified it a bit here:

// src/index.tsx

import ReactDOM from 'react-dom';

export Examples = {
   FooComponent: {
       async render(htmlElement, props) {
           const { default: Foo } = await import("./components/Foo");
           ReactDOM.render(<Foo {...props} />, htmlElement);
       }
   },
   BarComponent: {
       async render(htmlElement, props) {
           const { default: Bar } = await import("./components/Bar");
           ReactDOM.render(<Bar {...props} />, htmlElement);
       }
   }
};

When the webpack main bundle is downloaded using a <script src=''>, it creates an object on window called MyLibraryComponents. I can then render react components into the legacy app like this: MyLibraryComponents.Examples.FooComponent.render(...)

As more components are added to this library, I'm interested in potentially using Module Federation as a means to independently deploy components, and to isolate dependencies, etc.

However, in all the module federation project examples I've seen it is necessary to have a "bootstrap" file and have your webpack entry file do this. And then your "real" entry file to your app should be renamed to bootstrap.js:

import("./bootstrap")

Apparently, this ensures that the project's shared modules are loaded by the browser first, or something like that. The reason isn't 100% clear to me yet.

The issue I'm seeing is that my project's entry file actually has "exports" that my webpack library depends on, whereas if this was a traditional react app, it would just do something like this:

import ReactDOM from "react-dom";
import App from "./App;

ReactDOM.render(<App />, document.getElementById("root"));

If I update my entry point file to just import('./bootstrap'), then my library just ends up being an empty object when I inspect it in the console.

Is there a way I can write the 'bootstrap' entry file so that I can support module federation in this project?

Thank you for the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷︶言冷语的世界 2025-01-24 11:58:53

我需要更新我的新索引文件以执行这样的操作:

// index entry file

import("./bootstrap").then(MyLibraryComponents => {
      window.MyLibraryComponents = MyLibraryComponents;
});

使用引用窗口的任何代码。麦基里components需要确保现在存在,因为现在它被“加载”了异步。或者您可以做这样的事情:

setTimeout(() => {
    // Do something with window.MyLibraryComponents...
}, 1000);

I needed to update my new index file to do something like this:

// index entry file

import("./bootstrap").then(MyLibraryComponents => {
      window.MyLibraryComponents = MyLibraryComponents;
});

Any code using referencing window.MyLibraryComponents needs to ensure this exists now though since it's now being "loaded" asynchronously. Or you can do something like this:

setTimeout(() => {
    // Do something with window.MyLibraryComponents...
}, 1000);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文