Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React application with external plugins

I'm building a React application bundled using Parcel or Webpack.
The application should be able to embed external React components
developed by third-parties and hosted elsewhere as modern javascript modules:

// https://example.com/scripts/hello-plugin.js
import React from 'react';

export default class HelloPlugin extends React.Component {
    render() {
        return "Hello from external plugin!";
    }
}

Host application loads these components using asynchronous import like this, for example:

// createAsyncComponent.tsx
import * as React from 'react';
import { asyncComponent } from 'react-async-component';

export default function createAsyncComponent(url: string) {
    return asyncComponent({
        resolve: () => import(url).then(component => component.default),
        LoadingComponent: () => <div>Loading {url}....</div>,
        ErrorComponent: ({ error }) => <div>Couldn't load {url}: {error.message}</div>,
    })
}

But looks like bundlers don't allow importing arbitrary urls as external javascript modules.

Webpack emits build warnings: "the request of a dependency is an expression" and the import doesn't work. Parcel doesn't report any errors, but fails when import(url) occurs at runtime.

Webpack author recommends using scriptjs or little-loader for loading external scripts.
There is a working sample that loads an UMD component from arbitrary URL like this:

public componentDidMount() {
    // expose dependencies as globals
    window["React"] = React;
    window["PropTypes"] = PropTypes;

    // async load of remote UMD component
    $script(this.props.url, () => {
        const target = window[this.props.name];
        if (target) {
            this.setState({
                Component: target,
                error: null,
            })
        } else {
            this.setState({
                Component: null,
                error: `Cannot load component at ${this.props.url}`,
            })
        }
    });
}

Also, I saw a similar question answered a year ago where the suggested approach also involves passing variables via a window object.

But I'd like to avoid using globals given that most modern browsers support modules out of the box.

I'm wondering if it's possible. Perhaps, any way to instruct the bundler that my import(url) is not a request for the code-split chunk of a host application, but a request for loading an external Javascript module.

like image 600
yallie Avatar asked Jun 20 '18 13:06

yallie


People also ask

How do I add plugins to React?

If you install the "react-datepicker" package using npm i react-datepicker, the package will be downloaded to he node_modules folder of the project. You can then, import the react-datepicker and use in the files. require is not installed then. Try installing it using, npm i require.

Is it OK to use jQuery with React?

The main limitation of using jQuery in React is that jQuery manually updates the DOM. On the other hand, React has its system for making changes to the DOM. It internally determines when a React app or component should re-render. It also figures out which parts of the UI need to be updated.

Is it possible to integrate third party libraries with React?

React can be used in any web application. It can be embedded in other applications and, with a little care, other applications can be embedded in React.

How to include an external JavaScript library to ReactJS?

We are going to create a react application and include an external JavaScript library to ReactJS in three approaches. These are: Using react-script-tag Package. Using react-helmet Package. Using JavaScript DOM Methods. Step 1: Create a React application using the following command inside your terminal or command prompt:

How to add additional JS file in react app?

If you want to add additional js file (script). This is the easiest way to to do this. This is the root html file of your react application. According to your folder structure path can be changed.

Do you need plugin support for your ReactJS website?

Our ReactJS developers can create powerful plugins for your website and help you to get the utmost benefits. This post has complete information, incorporating example code. Also, if you are not developing an application that needs plugin support, you can apply these strategies to build powerful and large React applications.

What are the react add-ons?

The React add-ons are a collection of useful utility modules for building React apps. These should be considered experimental and tend to change more often than the core. createFragment, to create a set of externally-keyed children. The add-ons below are in the development (unminified) version of React only:


1 Answers

In the context of Webpack, you could do something like this:

import(/* webpackIgnore: true */'https://any.url/file.js')
  .then((response) => {
    response.main({ /* stuff from app plugins need... */ });
  });

Then your plugin file would have something like...

const main = (args) => console.log('The plugin was started.');
export { main };
export default main;

Notice you can send stuff from your app's runtime to the plugin at the initialization (i.e. when invoking main at the plugin) of the plugins so you don't end up depending on global variables.

You get caching for free as Webpack remembers (caches) that the given URL has already loaded so subsequent calls to import that URL will resolve immediately.

Note: this seems to work in Chrome, Safari & firefox but not Edge. I never bothered testing in IE or other browsers.

I've tried doing this same sort of load with UMD format on the plugin side and that doesn't seem to work with the way Webpack loads stuff. In fact it's interesting that variables declared as globals, don't end up in the window object of your runtime. You'd have to explicitly do window.aGlobalValue = ... to get something on the global scope.

Obviously you could also use requirejs - or similar - in your app and then just have your plugins follow that API.

like image 136
Roy Art Avatar answered Nov 15 '22 05:11

Roy Art