目标:为了支持基于某些安全性或定义的用户角色要求而动态加载Javascript模块,因此即使在开发工具中标识了模块名称,也无法通过控制台成功导入。
可以轻松地将Javascript模块上传到Firebase(#AskFirebase)之类的云存储服务,并可以根据自定义声明或类似测试的使用Firebase Cloud Function firebase.functions().httpsCallable("ghost");
有条件地检索代码。
export const ghost = functions.https.onCall(async (data, context) => {
if (! context.auth.token.restrictedAccess === true) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
}
const storage = new Storage();
const bucketName = 'bucket-name.appspot.com';
const srcFilename = 'RestrictedChunk.chunk.js';
// Downloads the file
const response = await storage
.bucket(bucketName)
.file(srcFilename).download();
const code = String.fromCharCode.apply(String, response[0])
return {source: code};
})
最后,我要做的是获取一个Webpack的React组件,将其放在云中,在服务器端进行安全检查后有条件地将其下载到客户端,然后import()
放入用户的客户端环境并进行渲染。
将Javascript存储在云中并有条件地下载到客户端非常容易。在客户端中有了webpack的代码后,就可以像使用Function(downloadedRestrictedComponent)
一样使用import('./RestrictedComponent')
将其添加到用户环境中,但是我不知道该如何获取从组件默认导出,这样我就可以实际渲染东西了。
import(pathToComponent)
返回已加载的模块,据我所知,没有选择传递import()
字符串或流,仅传递模块的路径。 Function(downloadedComponent)
会将下载的代码添加到客户端环境中,但我不知道如何访问模块的导出以呈现动态加载的React组件。
有什么方法可以从下载的流中动态导入Javascript模块吗?
编辑添加:感谢您的答复。不熟悉Blob和URL.createObjectURL
的细微差别。知道为什么会找不到吗?
const ghost = firebase.functions().httpsCallable("ghost");
const LoadableRestricted = Loadable({
// loader: () => import(/* webpackChunkName: "Restricted" */ "./Restricted"),
loader: async () => {
const ghostContents = await ghost();
console.log(ghostContents);
const myBlob = new Blob([ghostContents.data.source], {
type: "application/javascript"
});
console.log(myBlob);
const myURL = URL.createObjectURL(myBlob);
console.log(myURL);
return import(myURL);
},
render(loaded, props) {
console.log(loaded);
let Component = loaded.Restricted;
return <Component {...props} />;
},
loading: Loading,
delay: 2000
});
答案 0 :(得分:1)
将模块文件/流的内容读入BLOB。使用URL.createObjectURL()
创建指向BLOB的动态URL。现在按照上面的建议使用import
:
import(myBlobURL).then(module=>{/*doSomethingWithModule*/});
答案 1 :(得分:0)
您可以尝试使用React.lazy:
import React, {lazy, Suspense} from 'react';
const Example = () => {
const [userAuthenticated, setUserAuthenticated] = useState(true);
if (userAthenticated) {
const RestrictedComponent = lazy(() => import('./RestrictedComponent'));
return (
<div>
<Suspense fallback={<div><p>Loading...</p></div>}>
<RestrictedComponent />
</Suspense>
</div>
)
}
return (
<div>
<h1>404</h1>
<p>Restricted</p>
</div>
);
}
export default Example;