Next.js отображает приложение внутри html-разметки в виде строки
Мне нужно создать приложение Next.js внутри сторонней разметки html.
Наценка представлена следующим образом:
header.txt
<html>
<head>
<title>Some title</title>
</head>
<body>
<header>Some header</header>
<div>
footer.txt
</div>
<footer>Some footer</footer>
</body>
</html>
Эти файлы динамически создаются в папке. Когда я визуализирую свое приложение next.js, мне нужно обернуть их вокруг моего приложения.
Я создал рабочий пример, используя пакет под названием: html-response-parser
Я анализирую разметку из файлов в _document.js и ищу идентификатор настраиваемого элемента, который я заменяю следующим 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, которые реагируют, не могут использовать.
Возможно, решением было бы использовать опасно SetInnerHTML, но в этом случае я не могу ввести и.
// 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}}/>)
Если у кого-то есть идея, как мне удастся обернуть свое следующее приложение моей разметкой, исходящей из файлов, дайте мне совет.
2 ответа
Вы можете добиться этого с помощью собственного сервера,
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
чтобы помочь вам в этом.
Решил проблему с помощью опасно SetInnerHTML. В основном он не заботится о строковом синтаксисе, который вы ему передаете, поэтому я придумал следующее решение в _document.js:
<Html>
<html dangerouslySetInnerHTML={{__html: header}}/>
<Head />
<body>
<Main />
<NextScript />
</body>
<html dangerouslySetInnerHTML={{__html: footer}}/>
</Html>
Оба вызова опасно SetInnerHTML берут нечетное количество элементов и обертывают компоненты next.js.
К слову, если у кого-то есть другое решение, возможно, без опасного SetInnerHTML, прокомментируйте его.