【问题标题】:Writing embeddable Javascript plugin with React & Webpack使用 React 和 Webpack 编写可嵌入的 Javascript 插件
【发布时间】:2016-09-11 09:43:56
【问题描述】:

我希望能够将我的 React 应用程序与 Webpack 捆绑在一起,以便可以使用一组与客户端相关的配置来获取、调用和初始化放在 CDN 上的分布式副本。

看完thisthis,我的webpack入口文件设置如下:

// ... React requires etc.

(() => {
  this.MyApp = (config) => {
    // some constructor code here
  }

  MyApp.prototype.init = () => {
    ReactDOM.render(<MyReactApp config={MyApp.config} />, someSelector);
  }
})();

我的想法是在我的客户中,我可以执行以下操作:

<script src="./bundle.js" type="text/javascript"></script>
<script type="text/javascript">
  MyApp.init({
    some: "config"
  });
</script>

而我的 MyApp#init 函数将在客户端的某个容器内呈现我的 React 应用程序。

我是否以正确的方式思考这个问题?有没有更简单或更有效的方法来解决这个问题?

我的错误是 Uncaught TypeError: Cannot set property 'MyApp' of undefined,因为 IIFE 中的 thisundefined。我真的很想了解为什么会发生这种情况以及如何解决它的建议。

提前致谢!

【问题讨论】:

    标签: javascript reactjs webpack


    【解决方案1】:

    所以我找到了一个解决方案,如here所述

    如果我更改我的webpack.config.js 文件以将以下属性添加到output 对象,即

    var config = {
      // ...
      output: {
        // ...
        library: 'MyApp',
        libraryTarget: 'umd',
        umdNamedDefine: true,
      }
    }
    

    这将我与 webpack 捆绑的文件指定为 UMD 模块,所以如果我在该文件中有一个函数并将其导出...

    export const init = (config) => {
      ReactDOM.render(<MyReactApp config={config} />, someSelector);
    }
    

    然后,我可以在我的客户端中执行以下操作。

    <script src="./bundle.js" type="text/javascript"></script>
    <script type="text/javascript">
      MyApp.init({
        some: "config"
      }); 
    </script>
    

    然后我的 React 应用程序渲染。

    如果有人认为这是一种愚蠢的做法,我很想听听!

    有关 WEBPACK 配置的更多信息

    请记住,我已经有一段时间没有接触过这段代码了。鉴于它是 Javascript,世界可能已经向前发展,有些做法可能已经过时了。

    这是我的 React 入口点文件 (src/index.js)

    import 'babel-polyfill';
    import React from 'react';
    import { render } from 'react-dom';
    import Root from './components/Root';
    import configureStore from './lib/configureStore';
    
    const store = configureStore();
    
    export const init = (config) => {
      render(
        <Root store={store} config={config} />, 
        document.querySelector(config.selector || "")
      );
    }
    

    这是我的 Webpack 配置 (webpack.config.js)

    var webpack = require('webpack');
    var path = require('path');
    var loaders = require('./webpack.loaders');
    
    module.exports = {
        entry: [
            'webpack-dev-server/client?http://0.0.0.0:8080', // WebpackDevServer host and port
            'webpack/hot/only-dev-server',
            './src/index.js' // Your appʼs entry point
        ],
        devtool: process.env.WEBPACK_DEVTOOL || 'source-map',
        output: {
            path: path.join(__dirname, 'public'),
            filename: 'bundle.js',
            library: 'Foo',
            libraryTarget: 'umd',
            umdNamedDefine: true,
        },
        resolve: {
            extensions: ['', '.js', '.jsx']
        },
        module: {
            loaders: loaders
        },
        devServer: {
            contentBase: "./public",
                noInfo: true, //  --no-info option
                hot: true,
                inline: true
            },
        plugins: [
            new webpack.NoErrorsPlugin()
        ]
    };
    

    如您所见,我的 Webpack 配置输出我的 bundle.js,这是我的前端将摄取的内容。

    【讨论】:

    • 嗨,mattsch。这是一个很好的解决方案。我唯一的问题是如何检查该小部件是否集成在客户的网站上。因此,假设有一个应用程序并构建一个小部件。我会在应用程序中检查一些用户(通过 id 或主机名)在他们的网站上嵌入了一个小部件。
    • @To_wave 我想作为init 函数的一部分,您可以使用客户端的详细信息将请求ping 回您的服务器——这可能有效吗?
    • @mattsch 这仍然是您使用的方法吗?你遇到过什么问题吗?或者它工作得很好
    • @jasan 我们仍在使用这种方法,它不会给我们带来任何我们知道的问题。
    • @ThomasValadez 它在bundle.js 中导出。
    【解决方案2】:

    你的班级周围有围栏。

    MyApp 需要导出或附加到全局窗口对象,然后才能这样调用它。

    在您的情况下,您实际上不是在调用 MyApp.init(),而是在调用 window.MyApp.init(),但全局对象 window 没有附加对象 MyApp。

    // ... Simple attaching MyApp to the window (as a function)
    window.MyApp = (config) => {
      ...
    }
    
    // ... Using class and export
    class MyApp {
      constructor(config){...}
    }
    export default MyApp
    
    // or simply attach to the window
    window.MyApp = MyApp
    

    我更喜欢使用 export 创建类和导出模块。然后创建另一个文件仅用于附加到窗口。因为像这样将类附加到窗口并不是最佳实践。

    // Import module and attach it to the window
    import MyApp from '.my-app'
    window.MyApp = MyApp
    

    您可以寻找将模块导出为 UMD、AMD...的高级选项...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 2018-08-17
      • 1970-01-01
      • 2021-10-12
      • 2016-11-16
      • 2021-08-10
      • 2016-11-17
      相关资源
      最近更新 更多