簡體   English   中英

如何在 gulp/node 中預渲染 React 應用程序?

[英]How can I pre-render a react app in gulp/node?

如何在 gulp 和節點 12 中以編程方式呈現 React 應用程序?

我接管並將舊的 react (0.12.0) 應用程序升級到最新版本。 這也涉及升級到 ES6。 React 代碼本身已經完成,但我們還需要預渲染應用程序(該應用程序是一個交互式文檔,必須被搜索引擎抓取)。

以前,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。 我尋找了預制的解決方案,但它們似乎都針對舊的 React 版本,其中 react-tools 仍然存在。

我用 browserify & babel 打包了下面的特殊服務器端腳本,然后使用 runInNewContext 運行它。 它不會失敗但也不會輸出任何代碼,它只是記錄一個空對象

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 任務,它直接呈現應用程序組件,而不是上面的服務器端入口點腳本。 如果有人需要這樣做,這里有一個可行的解決方案。

使用vm.runInNewContext允許我們定義一個合成瀏覽器上下文,而require沒有。 如果您在應用程序的任何位置訪問window這很重要。

源代碼/服務器.js:

import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './index';

const content = renderToString(<App />);
global.output = content;

上面的腳本作為瀏覽器的入口點。 要編譯的 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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM