ReactJS错误通过变量呈现基本的html组件

时间:2015-06-04 19:20:17

标签: reactjs require fs

我正在尝试将jsx模板名称的字符串传递给一个组件,该组件将负责仅渲染没有交互的基本html组件(我们有很多)。

'use strict';

import React from 'react';

export default class TemplateLoader extends React.Component {
  displayName = 'TemplateLoader'

  constructor(props) {
    super(props);
  }

  render() {
    var template = require('./static-templates/'+this.props.template+'.jsx');
    return template(this);
  }
}

并且控制台中的输出是

    ./app/components/template-loader/static-templates/xxx.jsx
Module parse failed: /Users/xxx/Sites/xxx/app/components/template-loader/static-templates/c017-top-phones-reasons.jsx Line 1: Unexpected token <
You may need an appropriate loader to handle this file type.
| <div class="xxx">
|
| </div>;
 @ ./app/components/template-loader/static-templates ^\.\/.*\.jsx$

如果我将其切换到

'use strict';

import React from 'react';
import jsx from 'react-jsx';
import fs from 'fs';

export default class TemplateLoader extends React.Component {
  displayName = 'TemplateLoader'

  constructor(props) {
    super(props);
  }

  render() {
    var file = fs.readFileSync('./static-templates/'+this.props.template+'.jsx');
    var template = jsx.server(file, 'utf-8');
    return template(this);
  }
}

我得到了

Error: ENOENT, no such file or directory './static-templates/xxx.jsx'
    at Object.fs.openSync (fs.js:438:18)
    at Object.fs.readFileSync (fs.js:289:15)

如下面评论我的网站包装,我们使用Splash Pages for gocardless.com作为基础。我添加了html-loader,文件加载器,css-loader。

我的文件配置

node: {
  fs: "empty"
},
module: {
  loaders: [
    { test: /\.html$/, loader: "html-loader" },
    { test: /\.(jpe?g|png|gif|svg|eot|woff|ttf)$/, loader: 'file-loader' },
    { test: /\.js$/, exclude: /node_modules/, loaders: ['react-hot-loader', 'babel-loader'] },
    { test: /\.json$/, exclude: /node_modules/, loader: 'json-loader' },
    { test: /\.scss$/, loader: 'style-loader!css-loader!sass-loader' },
    { test: /\.css$/, loader: 'style-loader!css-loader' },
  ],
},

1 个答案:

答案 0 :(得分:1)

1。启用.jsx文件的编译

当遇到以.jsx结尾的文件时,通知Webpack使用babel-loader。见https://github.com/babel/babel-loader#usage

因此,请将以下内容添加到您的加载器列表中:

'{ test: /\.jsx$/, exclude: /node_modules/, loaders: ['react-hot-loader', 'babel-loader'] },'

修改现有测试,以便同时捕获.js.jsx

{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['react-hot-loader', 'babel-loader'] },
             ^^
              \- add x? here

此处,测试正则表达式中的?标记运算符显示“零或一”,因此它捕获.js.jsx

2。根据CommonJS约定

编写所需的模块

当您需要时,这将无效,因为没有导出任何内容。默认情况下,CommonJS模块中的所有内容对于该模块都是私有的,您必须显式导出您希望require的调用者接收的任何内容。所以这不起作用:

<div class="panel">

</div>;

而是导出JSX表达式:

module.exports = <div className="panel">
    I am static template 2!
</div>;

请参阅http://know.cujojs.com/tutorials/modules/authoring-cjs-modules

请记住,在JSX中,您没有使用直接HTML。您需要使用className而不是class。有关“普通”HTML的其他差异列表,请参阅https://facebook.github.io/react/docs/jsx-gotchas.html

3。使其与React工具一起使用

现在您找到,加载和编译了模板,它仍然无法呈现。你会收到这个错误:Uncaught ReferenceError: React is not defined或类似的错误。让我们来看看babel-loader生成的JavaScript,它将JSX转换为普通的旧JavaScript:

"use strict";

module.exports = React.createElement(  // <-- error here
  "div",
  { className: "panel" },
  "I am a static template 2!"
);

因此JSX转换的输出要求React在范围内。这是有道理的,因为JSX只是编写React.createElement(...的便捷语法。最后,要使所有内容协同工作,您的模板需要如下所示:

import React from 'react';
// or var React = require('react');

module.exports = <div className="panel">
    I am a static template 2!
</div>

警告:我没有尝试直接使用react-hot-loader,但它确实可以在webpack-dev-server下工作,我相信使用react-hot-loader。所以这应该可行,但它不会尝试删除react-hot-loader。

我的工作实现如下所示。请注意,我将模板作为prop传递,而不是在组件中计算它。我认为这是更惯用的React。这也使用了一些新的ES6语法来获得乐趣,但你使用的是babel,所以它应该没问题。不完全是你在做什么,而是关闭。有一点需要注意,最好是调用require一次(在构造函数中或在componentDidMount中),而不是在render函数中调用,这可以经常调用。

var StaticTemplateComponent = React.createClass({
    render: function () {
        return this.props.template;
    }
});

window.mountStaticComponent = (templateName, element) => {
    var templatePath = `./static-templates/${templateName}.jsx`;
    var template = require(templatePath);

    var staticTemplateComponent = React.createElement(StaticTemplateComponent, {template: template});
    React.render(staticTemplateComponent, element);
};

4。自动将静态模板包装在所需的CommonJS

超出问题的范围,并留给读者练习。应该可以编写一个自定义webpack加载器,它自动将模板包装在适当的导入/导出语句中。奖励点可自动将HTML5转换为兼容的JSX。

至于为什么它不能与jsx.server一起使用,我从未使用它。基于错误,我猜它会在你的文件的错误目录中查找,所以再次,可能是一个配置问题。