6

I've created React application and I need to generate embed code to other websites. It's large app where I want to do only one component as a widget for other domains. I have read Writing embeddable Javascript plugin with React & Webpack and How to embed react component on other domains?. I set my webpack, but still can't render the widget on another domain.

This widget should:

  1. be available via <script> tag, not iframe
  2. show only one part of the app (path /referral), but not all app

The widget is a button and popup, which displays by click on the button.

Here is my webpack.config.js in client folder:

const path = require('path');
const bundleOutputDir = './referral';
const env = require('yargs').argv.env;

module.exports = env => {
  const isDevBuild = !(env && env.prod);

  if (env === 'build') {
    mode = 'production';
  } else {
    mode = 'development';
  }

  return [
    {
      mode: mode,
      entry: './src/components/early-referrals/Referral.js',
      output: {
        filename: 'widget.js',
        path: path.resolve(bundleOutputDir),
        library: 'Referral',
        libraryTarget: 'umd',
        umdNamedDefine: true
      },
      devServer: {
        contentBase: bundleOutputDir
      },
      module: {
        rules: [
          { test: /\.html$/i, use: 'html-loader' },
          {
            test: /\.css$/i,
            use: [
              'style-loader',
              'css-loader' + (isDevBuild ? '' : '?minimize')
            ]
          },
          {
            test: /\.(png|jpe?g|gif)$/i,
            use: [
              {
                loader: 'file-loader'
              }
            ]
          },
          {
            test: /(\.jsx|\.js)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: [
                  [
                    '@babel/env',
                    {
                      targets: {
                        browsers: ['ie 6', 'safari 7']
                      }
                    }
                  ]
                ]
              }
            }
          }
        ]
      }
    }
  ];
};

Here is component RegisterReferral.js, which is entry point in webpack:

import PopupRef from '../popup/PopupRef';

const RegisterReferral = ({
...
}) => {
  const [...] = useState();

  useEffect(() => {
    ...
  }, []);

  return (
    <div>
        // some styles for button that displays popup
        <PopupRef />
    </div>
  );
};

const mapStateToProps = state => ({
  ...
});

export default connect(
  mapStateToProps,
  { ... }
)(RegisterReferral);

PopupRef.js is a component with popup, which should displays on other websites within the button.

In the App.js, I have the route for this component that I want to create as an embeddable:

<Route exact path="/referral" component={RegisterReferral} />

And this is a way how I paste the code on another domain:

// the URL in script is an URL of bundle file from webpack
<html>
    <head>
        <script src="http://example.com/client/referral/widget.js"  type="text/javascript"></script>   
    </head>
    <body>
        <p>Another website</p>
        <div id='app'></div>
    </body>
</html>

Also, I've tried to do entry point in webpack.config.js with Referral.js. And here is this component:

// Referral.js
import React from 'react';
import { render } from 'react-dom';
import App from './RegisterReferral.js';

render(<App />, document.getElementById('app'));

// At this case, webpack.config.js has 2 changes:
entry: './src/components/early-referrals/Referral.js',
output: {
        ...
        library: 'Referral',
      },

Nothing works. My component doesn't display on other websites.

Please help me to figure out what's wrong and how to embed one component (not all app) from React app on other websites.

Tony Ngo
  • 19,166
  • 4
  • 38
  • 60
Gammi
  • 101
  • 1
  • 2
  • 6

1 Answers1

0

Assume that you correctly config your webpack to bundle react js code

This is how I render the component in any page I want

Assume that I have this component

import React, {Component} from "react";
import {render} from "react-dom";

class LoginForm extends Component { }

render(<LoginForm/>, document.getElementById("loginForm")); // use render method

Edit:

Just saw your code I think you need also change the id in index.html

<div id="root"></div> 

to

<div id="referral"></div> 
Tony Ngo
  • 19,166
  • 4
  • 38
  • 60
  • Tony, thanks for reply! And how do you add the code with this component for another website, which doesn't have React? – Gammi Aug 11 '19 at 08:12
  • You need to bundle react with your code so do that it can run on another website :) – Tony Ngo Aug 11 '19 at 10:17
  • If my answer solve your problem make sure to vote up and and accepted my answer. Thanks you – Tony Ngo Aug 11 '19 at 10:17
  • I tried two ways and React shows me errors. I created component Referral.js, which now is a entry point in webpack. First, as you recommended, but I don't understand how this component to link with my RegisterReferral component: `import React, { Component } from 'react'; import { render } from 'react-dom'; class App extends Component {} render(, document.getElementById('referral'));` React now shows the error: `Target container is not a DOM element.` – Gammi Aug 11 '19 at 10:43
  • Second attempts that I tried with the same error: `import React from 'react'; import { render } from 'react-dom'; import RegisterReferral from './RegisterReferral.js'; render(, document.getElementById('referral'));` – Gammi Aug 11 '19 at 10:44
  • Sure, I will vote up and accept your answer, if it helps me to create embed code for other website. – Gammi Aug 11 '19 at 10:46
  • Do you have any div that have id referral ? – Tony Ngo Aug 11 '19 at 11:03
  • 1
    You can view my code [here](https://github.com/SaiGonSoftware/Awesome-CMS-Core/blob/master/src/AwesomeCMSCore/AwesomeCMSCore/webpack.config.js#L13) Basically you need to have entry point that include anything you need to run the component in the website – Tony Ngo Aug 11 '19 at 11:04
  • Yes, I have div with id referral. In the question, I showed the code that I paste on another website. I only changed id="app" to id="referral" in the real app. I'll view your code. Thanks for sharing it. – Gammi Aug 11 '19 at 11:51
  • 1
    [this](https://stackoverflow.com/questions/26566317/invariant-violation-registercomponent-target-container-is-not-a-dom-elem) may be help you – Tony Ngo Aug 11 '19 at 12:38
  • The problem with this error is that I don't use the widget on DOM of React application. It's widget for other websites. I mean that I have only widget component in the app and common index.html for the whole app. There is only id="root" in the index.html. Where should I put id="referral" in the React app, in this case? – Gammi Aug 12 '19 at 09:06
  • At the moment, I've viewed your webpack config, updates my own config, but can't start server because of this error. – Gammi Aug 12 '19 at 09:09
  • Can you share your project in github ? – Tony Ngo Aug 12 '19 at 09:11
  • I can't share the whole project, but I can share widget components and webpack config. Does it work for you? – Gammi Aug 12 '19 at 09:46
  • https://github.com/a007mr/widget Here is all staff for widget, including webpack config and main index.html. Structure is the same as in the real project. – Gammi Aug 12 '19 at 09:56
  • Now working. Yeah, it helps with target container error, but widget doesn't work on another website. – Gammi Aug 12 '19 at 15:52