【问题标题】:Next.js render app inside html markup coming as stringNext.js 在 html 标记中呈现应用程序,以字符串形式出现
【发布时间】:2020-06-06 23:17:35
【问题描述】:

我需要在第三方 html 标记中构建我的 Next.js 应用程序。

标记如下:

header.txt

<html>
  <head>
    <title>Some title</title>
  </head>
  <body>
    <header>Some header</header>
    <div>

页脚.txt

    </div>
    <footer>Some footer</footer>
  </body>
</html>

这些文件是动态生成到一个文件夹中的。当我渲染我的 next.js 应用程序时,我需要将它们包裹在我的应用程序周围。

我使用名为 html-react-parser 的包创建了一个工作示例

我从 _document.js 中的文件中解析标记,我正在寻找一个自定义元素 id,我将用下一个 js 应用程序替换它,如下所示:

const header = fs.readFileSync(path.resolve(ROOT + '/resources', 'header.txt'), 'utf8');
const footer = fs.readFileSync(path.resolve(ROOT + '/resources', 'footer.txt'), 'utf8');
const shell = `
    ${header}
    <main id="react-app"></main>
    ${footer}
`;


// later in the render method od _document.js:

render() {
        return (
            <React.Fragment>
                {parse(shell, {
                    replace: domNode => {
                        if (domNode.attribs && domNode.attribs.id === 'react-app') {
                            return (
                                <React.Fragment>
                                    <Main/>
                                    <NextScript/>
                                </React.Fragment>
                            )
                        }
                    }
                })}
            </React.Fragment>
        )
    }

虽然这可行,但我的问题是,这不是 html-react-parser 的目的,因为它将文件的标记转换为反应组件,并在转换过程中抛出许多关于错误使用的 html props 的警告。不能用。

也许解决方案是使用 dangerouslySetInnerHTML,但在这种情况下我不能注入和 .

// it fails because it wont treat the components as normal html
// <Main/><NextScript/> are not evaluated
      

const header = fs.readFileSync(path.resolve(ROOT + '/resources', 'header.txt'), 'utf8');
const footer = fs.readFileSync(path.resolve(ROOT + '/resources', 'footer.txt'), 'utf8');
const shell = `
    ${header}
      <React.Fragment>
        <Main/>
        <NextScript/>
      </React.Fragment>
    ${footer}
`;

// later in the render method od _document.js:

render(<html dangerouslySetInnerHTML={{__html: shell}}/>)

如果有人有想法,我该如何设法将我的下一个应用程序包装在来自文件的标记周围,请给我一些建议。

【问题讨论】:

    标签: javascript reactjs next.js server-side-rendering html-react-parser


    【解决方案1】:

    您可以通过custom server 实现这一目标,

    const express = require('express')
    const next = require('next')
    
    const header = fs.readFileSync(path.resolve(ROOT + '/resources', 'header.txt'), 'utf8');
    const footer = fs.readFileSync(path.resolve(ROOT + '/resources', 'footer.txt'), 'utf8');
    
    const port = parseInt(process.env.PORT, 10) || 3000
    const dev = process.env.NODE_ENV !== 'production'
    const app = next({ dev })
    const handle = app.getRequestHandler()
    
    app.prepare().then(() => {
      const server = express()
    
      server.all('*', async (req, res) => {
        const nextResponse = await handle(req, res);
        return mergeHTML(header, footer, nextResponse); // You will need to "merge" cause nextResponse has `head` & `body` as well.
      })
    
      server.listen(port, err => {
        if (err) throw err
        console.log(`> Ready on http://localhost:${port}`)
      })
    })
    

    mergeHTML 应该合并你的header 的头部和下一个的头部和身体。您可以使用cheerio 来帮助您。

    【讨论】:

    • 谢谢,这行得通,尽管最后我以不同的方式解决了它。我将其发布为我的问题的答案。
    【解决方案2】:

    我使用 dangerouslySetInnerHTML 解决了这个问题。基本上它不关心你传入的字符串语法,所以我在 _document.js 中提出了以下解决方案:

    <Html>
      <html dangerouslySetInnerHTML={{__html: header}}/>
      <Head />
      <body>
          <Main />
          <NextScript />
      </body>
      <html dangerouslySetInnerHTML={{__html: footer}}/>
    </Html>

    dangerlySetInnerHTML 的两个调用都采用奇数个元素并环绕 next.js 组件。

    如果有人有其他解决方案可能没有危险的SetInnerHTML,请发表评论。

    【讨论】:

      猜你喜欢
      • 2017-06-10
      • 2018-09-22
      • 2014-05-27
      • 2019-06-04
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 2016-05-21
      • 2021-02-20
      相关资源
      最近更新 更多