我正在尝试将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' },
],
},
答案 0 :(得分:1)
当遇到以.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
。
当您需要时,这将无效,因为没有导出任何内容。默认情况下,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。
现在您找到,加载和编译了模板,它仍然无法呈现。你会收到这个错误: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);
};
超出问题的范围,并留给读者练习。应该可以编写一个自定义webpack加载器,它自动将模板包装在适当的导入/导出语句中。奖励点可自动将HTML5转换为兼容的JSX。
至于为什么它不能与jsx.server
一起使用,我从未使用它。基于错误,我猜它会在你的文件的错误目录中查找,所以再次,可能是一个配置问题。