Next.js render app inside html markup coming as string

China☆狼群 提交于 2021-01-28 03:15:38

问题


I need to build my Next.js app inside a third-party html markup.

The markup is given as follows:

header.txt

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

footer.txt

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

This files are dynamically generated into a folder. When I render my next.js application, I need to wrap them around my application.

I created a working example using the package called: html-react-parser

I parse the markup from the files in the _document.js and I am looking for a custom element id which I am replacing with the next js app as follows:

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>
        )
    }

Although this works, my problem is, that this is not the purpose of the html-react-parser because it converts the markup of the files to react components, and throws many warnings during the conversion about wrongly used html props which react can not use.

Maybe the solution would be to use dangerouslySetInnerHTML, but in this case I can not inject and .

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

If anybody has an Idea how could I manage to wrap my next app around my markup coming from the files, please give me some advice.


回答1:


You can achieve that with 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 should merge head from your header & next's head & the body. You can use cheerio to help you with that.




回答2:


I solved the problem using dangerouslySetInnerHTML. Basically It does not care about the string syntax you pass into it, so I came up with the following solution in _document.js:

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

Both calls of dangerouslySetInnerHTML are taking the odd number of elements and wrapping around the next.js components.

By the was if anybody has an another solution maybe without dangerouslySetInnerHTML please comment it.



来源:https://stackoverflow.com/questions/60357068/next-js-render-app-inside-html-markup-coming-as-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!