wix-incubator / react-templates

Light weight templates for react
https://wix.github.io/react-templates
MIT License
2.82k stars 207 forks source link

Cannot find module when using rt-import #187

Closed davenlin19 closed 8 years ago

davenlin19 commented 8 years ago

Hello,

I'd like to import a template in another template but it didn't work:

Header.rt: <rt-import name="Presentation" from="./Presentation" /> <Presentation></Presentation>

I'm pretty sure that i have Presentation.jsx and Presentation.rt in the same folder with Header.rt but i still have this error:

Cannot find module: './Presentation'

Thank you in advance !

nippur72 commented 8 years ago

Assuming you are using commonjs modules, react-templates exports the render function "as a whole", e.g.:

module.exports = function ...;

that means you cannot import them with name="Presentation", but you have to use:

<rt-import name="*" as="Presentation" from="./Presentation" />

this seems somewhat counterintuitive, but it mimics the ES6 import syntax:

import * as Presentation from "./Presentation";

You can also use the old rt-require:

<rt-require dependency="./Presentation" as="Presentation" />
davenlin19 commented 8 years ago

Thanks for your answer. I tried to use

<rt-import name="*" as="Presentation" from="./Presentation" />

and change the extension of this file Presentation.jsx to Presentation.js so i don't have any problem with the compilation.

But i still cannot use <Presentation></Presentation> in the Header.rt file. My page becomes blank and there are some errors in the browser's console:

warning.js:36 Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of 'Header'.

invariant.js:38 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method ofHeader.

Do you know how to fix it ? Thank you !

nippur72 commented 8 years ago

If you have this:

<rt-import name="*" as="Presentation" from="./Presentation" />
<Presentation></Presentation>

then Presentation can be one of the following:

  1. a stateless react component made directly from a .rt template using the rt-stateless attribute.
  2. a stateful react component, made from a .js file and .rt

Examples: Case 1: stateless component using only react-templates:

<!-- presentation.rt -->
<div rt-stateless>I am presentation</div>

Case 2: stateful component

<!-- presentation-template.rt -->
<div>I am presentation</div>
// presentation.js 
import { React } from "react";
class Presentation extends React.Component { }
Presentation.prototype.render = require('presentation-template');
module.exports = Presentation;
davenlin19 commented 8 years ago

Thank you very much. You save my life !

Yes, my Presentation is stateful. I think i don't quite understand why but in my Presentation.js, i changed from

export default class Presentation extends React.Component

to

class Presentation extends React.Component ... module.exports = Presentation

and it works.

steezeburger commented 7 years ago

This is happening to me too but only when using rt-import in a nested component. I have a components directory in an index.js that exports all my components as named exports. This works great everywhere, and I don't get an error about a file not existing or anything, it just isn't a proper React component.

Any idea what could be causing this?

nippur72 commented 7 years ago

@steezeburger can you post an example of what is not working? I'm sure it's only a matter of the way things are exported.

steezeburger commented 7 years ago

I figured out this was an error with react-templates-loader, modules type, and import/export. I had an index.js in my component directory that exported all components. I had webpack set up with a root resolve so that I could use from="component" in my rt-imports. This worked fine until I tried using that convention in a nested component (container > one level deep component (works) > two level deep (doesn't work)). It worked using name="default" and specifying the relative path however. I tried changing modules to es6 and began getting other, different errors about import being an unexpected token.

We actually got a new developer recently which allowed us to drop our dependency on our designer writing markup, so we've since moved away from react templates however, so this is no longer an issue.

kelsonic commented 7 years ago

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of 'App'.

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of App.

I get the same error as @davenlin19 and the suggested fixes did not work. I am using ES6 and webpack.

App Component

import React, { Component } from 'react';
import { connect } from 'react-redux';
import selectAppDetails from './selectors';
import view from './view.rt';

class App extends Component {
}

App.prototype.render = view;

const mapStateToProps = selectAppDetails();

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

App view.rt

<rt-import name="*" as="SomeComponent" from="../../containers/SomeComponent" />
<div>
  <SomeComponent />
</div>

SomeComponent

import React, { PureComponent } from 'react';
import view from './view.rt';

class SomeComponent extends PureComponent {
}

SomeComponent.prototype.render = view;

export default SomeComponent;

SomeComponent view.rt

<div>
  Some component
</div>

Inside Webpack loaders configuration

{
  test: /\.rt$/,
  loaders: [ "babel-loader?presets[]=es2015", "react-templates-loader?modules=es6" ]
},

Any suggestions?

nippur72 commented 7 years ago

in SomeComponent, what are Address and view (e.g. where you define them?)

kelsonic commented 7 years ago

@nippur72 Sorry, that was bad pasting on my part. I edited my comment.

nippur72 commented 7 years ago

SomeComponent is exported as default but later imported as "*". You need to be consistent between import/export.

kelsonic commented 7 years ago

I get the same error when I import it as such: <rt-import name="default" as="SomeComponent" from="../../components/SomeComponent" />

kelsonic commented 7 years ago

I found the solution:

SomeComponent

import React, { PureComponent } from 'react';
import view from './view.rt';

class SomeComponent extends PureComponent {
}

SomeComponent.prototype.render = view;

module.exports = SomeComponent;

instead of using export default SomeComponent.

App view.rt

<rt-import name="default" as="SomeComponent" from="../../components/SomeComponent" />
<div>
  <SomeComponent />
</div>

instead of <rt-import name="*" as="SomeComponent" from="../../components/SomeComponent" /> as you suggested @nippur72.

Thanks for the help! :)