我正在构建一个使用 Parcel 或 Webpack 捆绑的 React 应用程序。
应用程序应该能够嵌入外部 React 组件
由第三方开发并作为现代 javascript 模块托管在其他地方:
// https://example.com/scripts/hello-plugin.js
import React from 'react';
export default class HelloPlugin extends React.Component {
render() {
return "Hello from external plugin!";
}
}
宿主应用程序像这样使用异步导入加载这些组件,例如:
// 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>,
})
}
但看起来 bundler 不允许将任意 url 作为外部 javascript 模块导入。
Webpack 发出构建警告:“依赖项的请求是一个表达式”并且导入不起作用。 Parcel 不报告任何错误,但在运行时发生 import(url) 时失败。
Webpack作者推荐使用scriptjs或者little-loader加载外部脚本。
有 a working sample从任意 URL 加载 UMD 组件,如下所示:
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}`,
})
}
});
}
此外,我还看到一个 similar question一年前回答,其中建议的方法还涉及通过窗口对象传递变量。
但我想避免使用全局变量,因为大多数现代浏览器都支持开箱即用的模块。
我想知道这是否可能。也许,以任何方式指示 bundler 我的 import(url) 不是对主机应用程序的代码拆分块的请求,而是对加载外部 Javascript 模块的请求。
最佳答案
在 Webpack 的上下文中,你可以这样做:
import(/* webpackIgnore: true */'https://any.url/file.js')
.then((response) => {
response.main({ /* stuff from app plugins need... */ });
});
然后你的插件文件会有类似...
const main = (args) => console.log('The plugin was started.');
export { main };
export default main;
请注意,您可以在插件初始化时(即在插件中调用 main 时)将内容从应用程序的运行时发送到插件,这样您就不会最终依赖于全局变量。
您可以免费获得缓存,因为 Webpack 会记住(缓存)给定的 URL 已经加载,因此后续导入该 URL 的调用将立即解析。
注意:这似乎适用于 Chrome、Safari 和 firefox,但不适用于 Edge。我从不在 IE 或其他浏览器中进行测试。
我已经尝试在插件端使用 UMD 格式进行相同类型的加载,但它似乎不适用于 Webpack 加载内容的方式。事实上,声明为全局变量的变量不会在运行时的窗口对象中结束,这很有趣。您必须显式执行 window.aGlobalValue = ...
才能在全局范围内获取某些内容。
显然,您也可以在您的应用中使用 requirejs - 或类似的东西,然后让您的插件遵循该 API。
关于reactjs - 使用外部插件 react 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50948995/