【问题标题】:Dynamic import of Javascript module from stream从流中动态导入 Javascript 模块
【发布时间】:2019-03-24 13:00:12
【问题描述】:

目标:支持根据某些安全性或已定义的用户角色要求动态加载 Javascript 模块,这样即使在开发工具中识别了模块的名称,也无法通过控制台。

JavaScript 模块可以轻松上传到 Firebase (#AskFirebase) 等云存储服务,并且可以根据自定义声明或类似测试的存在使用 Firebase 云函数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
});

【问题讨论】:

  • 您有没有找到自己喜欢的完整解决方案?
  • Shaz 或其他任何人:对这个问题有完整的解决方案吗? 我想分配 +500 赏金,但没有人加紧,明天将在我的控制之外到期。
  • @kjhughes 如果我理解正确,您将文件下载到目录./RestrictedComponent.js,如果用户已通过身份验证,导入该组件?是这样,你考虑过React.lazy吗?
  • @radihuq: React.lazy 可能有助于动态导入方面(谢谢),但它本身并不能阻止未经身份验证的用户通过从端点获取受限 JavaScript 从服务器检索受限制的 JavaScript。客户端 UI 检查。
  • @kjhughes 啊,好吧,我明白了。也许服务器端渲染是解决方案,或者something like this,但我对此没有太多经验。祝你好运!

标签: javascript reactjs firebase webpack react-loadable


【解决方案1】:

将模块文件/流的内容读入 BLOB。使用URL.createObjectURL() 创建您的BLOB 动态URL。现在按照上面的建议使用import

import(myBlobURL).then(module=>{/*doSomethingWithModule*/});

【讨论】:

  • 感谢@Randy Casburn,在上面编辑时出现“找不到模块...”错误。
  • 从来不知道这个blob的东西;所以要考虑的一件事(很明显)是那里提供的 js 代码将是编译的 js。但是 webpack 不仅编译 JS,还用自己的导入逻辑替换了导入。想象一下,您导入的这个文件是代码拆分的,并且可以触发其他导入...
  • @wkrueger:请注意,OP 的模块是后 Webpack 的。另请注意,我对完整工作代码示例的兴趣不仅限于 Randy 的基于 blob 的方法。谢谢。
【解决方案2】:

你可以试试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;

【讨论】:

  • 这个问题与 React 无关,是关于导入 streamsblob 而不是 urls
猜你喜欢
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 2021-12-23
  • 2020-07-25
  • 2011-04-17
相关资源
最近更新 更多