如何在 gulp/node 中预渲染 React 应用程序?
How can I pre-render a react app in gulp/node?
如何以编程方式在 gulp 和节点 12 中呈现 React 应用程序?
我接管了一个旧的 React (0.12.0) 应用并将其升级到最新版本。这也涉及升级到 ES6。 React代码本身就搞定了,但是我们还需要prerender应用(app是交互文档,必须要被搜索引擎抓取)。
以前,gulp 构建过程 运行 browserify 代码,然后 运行 使用 vm.runInContext:
// source code for the bundle
const component = path.resolve(SRC_DIR + subDir, relComponent);
vm.runInNewContext(
fs.readFileSync(BUILD_DIR + 'bundle.js') + // ugly
'\nrequire("react").renderToString(' +
'require("react").createElement(require(component)))',
{
global: {
React: React,
Immutable: Immutable,
},
window: {},
component: component,
console: console,
}
);
我很惊讶它以前有效,但它确实有效。但是现在它失败了,因为源码使用了ES6。
我寻找预制的解决方案,但它们似乎都针对旧的反应版本,其中反应工具仍然存在。
我用 browserify 和 babel 打包了下面的特殊服务器端脚本,然后 运行 使用 运行InNewContext。它不会失败但也不会输出任何代码,它只是记录一个空对象
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
我找到了很多关于“服务器端渲染”的文章,但它们似乎都是关于使用 express 渲染的,并且使用与上面脚本相同的行。我不能 运行 直接在 gulp 中编写该代码,因为它不能很好地与 ES6 导入一起使用,ES6 导入仅在节点 14 之后可用(并且是实验性的)。
我未能显示 gulp-browserify 任务,它直接呈现应用程序组件,而不是上面的 server-side 入口点脚本。如果有人需要这样做,这里有一个可行的解决方案。
使用 vm.runInNewContext
允许我们定义合成浏览器上下文,而 require
则不能。如果您在应用程序的任何位置访问 window
,这一点很重要。
src/server.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
global.output = content;
以上脚本作为 browserify 的入口点。 Gulp 要编译的任务:
function gulpJS() {
const sourcePath = path.join(SRC_DIR, 'src/server.js');
return browserify(sourcePath, { debug:true })
.transform('babelify', {
presets: [
["@babel/preset-env", { targets: "> 0.25%, not dead" }],
"@babel/preset-react",
],
})
.bundle()
.pipe(source('server_output.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('.'))
.pipe(dest(BUILD_DIR));
}
生成的文件现在可以用于以后的任务,例如将呈现的内容插入 HTML 文件。
const componentContent = fs.readFileSync(path.join(BUILD_DIR, 'server.js'));
const context = {
global: {
React: React,
Immutable: Immutable,
data: {
Immutable
},
},
window: {
addEventListener() { /* fake */ },
removeEventListener() { /* fake */ },
},
console,
};
vm.runInNewContext(componentContent, context);
const result = context.global.output;
如何以编程方式在 gulp 和节点 12 中呈现 React 应用程序?
我接管了一个旧的 React (0.12.0) 应用并将其升级到最新版本。这也涉及升级到 ES6。 React代码本身就搞定了,但是我们还需要prerender应用(app是交互文档,必须要被搜索引擎抓取)。
以前,gulp 构建过程 运行 browserify 代码,然后 运行 使用 vm.runInContext:
// source code for the bundle
const component = path.resolve(SRC_DIR + subDir, relComponent);
vm.runInNewContext(
fs.readFileSync(BUILD_DIR + 'bundle.js') + // ugly
'\nrequire("react").renderToString(' +
'require("react").createElement(require(component)))',
{
global: {
React: React,
Immutable: Immutable,
},
window: {},
component: component,
console: console,
}
);
我很惊讶它以前有效,但它确实有效。但是现在它失败了,因为源码使用了ES6。 我寻找预制的解决方案,但它们似乎都针对旧的反应版本,其中反应工具仍然存在。
我用 browserify 和 babel 打包了下面的特殊服务器端脚本,然后 运行 使用 运行InNewContext。它不会失败但也不会输出任何代码,它只是记录一个空对象
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
我找到了很多关于“服务器端渲染”的文章,但它们似乎都是关于使用 express 渲染的,并且使用与上面脚本相同的行。我不能 运行 直接在 gulp 中编写该代码,因为它不能很好地与 ES6 导入一起使用,ES6 导入仅在节点 14 之后可用(并且是实验性的)。
我未能显示 gulp-browserify 任务,它直接呈现应用程序组件,而不是上面的 server-side 入口点脚本。如果有人需要这样做,这里有一个可行的解决方案。
使用 vm.runInNewContext
允许我们定义合成浏览器上下文,而 require
则不能。如果您在应用程序的任何位置访问 window
,这一点很重要。
src/server.js:
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';
const content = renderToString(<App />);
global.output = content;
以上脚本作为 browserify 的入口点。 Gulp 要编译的任务:
function gulpJS() {
const sourcePath = path.join(SRC_DIR, 'src/server.js');
return browserify(sourcePath, { debug:true })
.transform('babelify', {
presets: [
["@babel/preset-env", { targets: "> 0.25%, not dead" }],
"@babel/preset-react",
],
})
.bundle()
.pipe(source('server_output.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('.'))
.pipe(dest(BUILD_DIR));
}
生成的文件现在可以用于以后的任务,例如将呈现的内容插入 HTML 文件。
const componentContent = fs.readFileSync(path.join(BUILD_DIR, 'server.js'));
const context = {
global: {
React: React,
Immutable: Immutable,
data: {
Immutable
},
},
window: {
addEventListener() { /* fake */ },
removeEventListener() { /* fake */ },
},
console,
};
vm.runInNewContext(componentContent, context);
const result = context.global.output;