Создание встраиваемого Javascript-плагина с помощью React & Webpack

Я хочу иметь возможность связывать приложение React с Webpack таким образом, чтобы распределенные копии, помещенные на CDN, могли быть получены, вызваны и инициализированы с помощью конфигурации конфигурации, относящейся к клиенту.

После прочтения этого и this, я настраиваю свою запись в 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, так как this внутри IIFE undefined. Мне бы очень хотелось понять, почему это происходит, и советы о том, как это исправить.

Спасибо заранее!

Ответ 1

Так что я вроде нашел решение этой проблемы, как описано здесь

Если я изменю свой файл webpack.config.js, добавив следующие атрибуты к объекту output, т.е.

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

Здесь указывается файл, который я связываю с веб-пакетом в качестве модуля 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: 'CreditKudos',
    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, который будет принимать мой интерфейс.

Ответ 2

У вас есть приложение вокруг вашего класса.

MyApp необходимо экспортировать или привязать к глобальному объекту окна, прежде чем вы сможете так его вызвать.

В вашей ситуации вы фактически не вызываете MyApp.init(), но вы вызываете window.MyApp.init(), но в глобальном объектном окне нет объекта 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

Я бы предпочел создать модуль класса и экспорта с помощью экспорта. Затем создайте другой файл только для прикрепления к окну. Поскольку это не считается лучшей практикой, чтобы прикрепить классы к окну.

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

Вы можете искать расширенные опции экспорта модулей как UMD, AMD...