在ES6中导入服务器端呈现的组件

时间:2015-12-05 02:55:54

标签: javascript node.js reactjs ecmascript-6

我有一个很好的小ES6 React组件文件(为此解释简化)。它使用特定于浏览器的库store这一切都在浏览器上运行得很漂亮:

/app/components/HelloWorld.js:

import React, { Component } from 'react';
import store from 'store';

export default class HelloWorld extends Component {
  componentDidMount() {
    store.set('my-local-data', 'foo-bar-baz');
  }

  render() {
    return (
      <div className="hello-world">Hello World</div>
    );
  }
}

现在,我正在尝试使用babel-register在服务器上进行渲染,如下所示:

/server/routes/hello-world.js:

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import HelloWorld from '../../app/components/HelloWorld'

export default function(req, res) {
  res.render('root', {
    reactHTML: ReactDOMServer.renderToString(<HelloWorld />),
  });
}

由于导入“store”,我从节点服务器收到“未定义窗口”的错误。理想情况下,我可以通过检测环境(节点与浏览器)有条件地导入,但ES6不支持条件导入。

解决这个问题的最佳方法是什么?我实际上并不需要执行浏览器代码(在这种情况下componentDidMount将不会被ReactDOMServer.renderToString调用)只是让它从节点运行。

2 个答案:

答案 0 :(得分:1)

一种方法是使用babel-rewire-plugin。您可以通过plugins选项

将其添加到babel-register
require('babel/register')({
  plugins: ['babel-rewire-plugin']
});

然后将您的store依赖关系重新连接到模拟商店:

HelloWorld.__Rewire__('store', {
  set: () => {} // no-op
});

您现在可以安静地从服务器渲染HelloWorld。

答案 1 :(得分:0)

如果你想抑制某些npm模块的负载,你可以模拟它。

require.cache[require.resolve('store')] = { exports: { set() {} // no-op } }; 导入:

之前,将它放在node.js应用程序设置中
var mytabs = [{
  name: "Marc"
}, {
  name: "Josef"
}, {
  name: "Luis"
}];
$('#tabs').tabs();
$.each(mytabs, function(indexInArray, myobj) {
  $('#tabs').find('li> a').eq(indexInArray).text(myobj.name);
});

将使用此值代替实际模块,而不需要用于您的目的。 Node.js模块API是稳定的,因此不会破坏此行为,您可以依赖它。