首页 > 解决方案 > 使用带有 react-rails 预渲染的嵌套文件夹

问题描述

我正在尝试react-rails为我的应用程序(https://github.com/reactjs/react-rails)进行设置。

最初设置它没有问题,但我预计会有很多不同的单独组件,所以我想/javascript/components整齐地组织我的文件夹。

所以我有这样的东西

components
 character
   avatar-selector
     AvatarSelector.tsx
 HomeLogo.tsx

AvatarSelector.tsx默认导出组件。

我有

const componentRequireContext = require.context("components", true);
const ReactRailsUJS = require("react_ujs");
ReactRailsUJS.useContext(componentRequireContext);

在两者packs/application.jspacks/server-rendering.js

当我渲染HomeLogo组件时,无论有没有预渲染,一切都很好。当我然后去渲染组件时,react_component('character/avatar-selector/AvatarSelector', avatar_props, prerender: false)它也可以正常工作。

但是当我切换到prerender: true它时会出错。

ExecJS::ProgramError: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.>" when prerendering character/avatar-selector/AvatarSelector

我已经尝试过直接添加

const AvatarSelector = require('../components/character/avatar-selector/AvatarSelector')

到我的包并尝试将组件渲染为AvatarSelector但我仍然遇到相同的错误。

标签: ruby-on-railsreactjsreact-railsexecjsserver-rendering

解决方案


 Regarding Encountered error <ExecJS::ProgramError: Invariant Violation: Element type is invalid: ...:

我认为核心问题之一是模块查找使用 try...catch。虽然错误被记录到控制台 shim 中,但这通常无济于事,因为以后的错误(例如不变违规)将导致致命错误(触发 500)。如果可以根据环境将其重构为更加有意(而不是仅仅根据异常做出反应,或者至少,如果捕获的异常不是很具体,则抛出)

EDIT: Here's something you can do to help with the Invariant Violation bug:

In app/javascripts/packs/server_rendering.js, replace ReactRailsUJS.useContext('require.context('components', true)); with

// So that we don't fall back to the global namespace (which leads to hard to
// parse errors).
function fromRequireContext(reqctx) {
  return function(className) {
    const parts = className.split('.');
    const filename = parts.shift();
    const keys = parts;
    // Load the module:
    let component = reqctx('./' + filename);
    // Then access each key:
    keys.forEach((k) => {
      component = component[k];
    });
    // support `export default`
    if (component.__esModule) {
      component = component.default;
    }
    return component;
  };
}
ReactRailsUJS.getConstructor = fromRequireContext(require.context('components', true));

参考 - https://github.com/reactjs/react-rails/issues/264


推荐阅读