在ES6中导入用于服务器端渲染的组件

Import components for server-side rendering in ES6

本文关键字:组件 服务器端 用于 ES6 导入      更新时间:2023-09-26

我有一个很好的小ES6-React组件文件(为了这个解释而简化)。它使用了一个特定于浏览器的库,存储这一切在浏览器上都能很好地工作:

/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 />),
  });
}

由于导入"存储",我从节点服务器收到一个错误,称"未定义窗口"。理想情况下,我可以通过检测环境(节点与浏览器)进行有条件导入,但ES6中不支持有条件导入。

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

一种方法是使用babel rewire插件。您可以通过plugins选项将其添加到babel寄存器

require('babel/register')({
  plugins: ['babel-rewire-plugin']
});

然后将你的store依赖重新连接到一个模拟商店:

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

现在,您可以从服务器和平地渲染HelloWorld。

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

HelloWorld.js导入之前,将其放在node.js应用程序设置中:

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

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