'Next.js and Webpack inline Javascript or CSS ressources
I have the following use case: I need to generate static files with React and Next.js. For that I extended the next.config.js with the following content:
module.exports = {
exportTrailingSlash: true,
exportPathMap: async function () {
const paths = {
'/': { page: '/' }
}
const errorPages = [
{ id: 1, name: '404', lang: 'en' },
{ id: 2, name: '500', lang: 'en' }
]
errorPages.forEach(errorPage => {
paths[`/errorPage/${errorPage.id}`] = {
page: '/errorPage/[id]',
query: { id: errorPage.id }
}
})
return paths
},
}
This totally works. The files are beeing generated in the out
folder after npm export
An additional use case however is this one:
The index.html file needs to work everywhere, not just in the exact place it has in the out
folder. For example another webapp queries an API which scans the index.html and returns the html as string from that file. This html string has to work, but the references for the js files/bundles are relative (see link and script tags):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width,minimum-scale=1,initial-scale=1"
/>
<meta name="next-head-count" content="2" />
<link
rel="preload"
href="/_next/static/UkokJ2QynwMCza2ya8Vuz/pages/index.js"
as="script"
/>
<link
rel="preload"
href="/_next/static/UkokJ2QynwMCza2ya8Vuz/pages/_app.js"
as="script"
/>
<link
rel="preload"
href="/_next/static/runtime/webpack-91b117697e716c22a78b.js"
as="script"
/>
<link
rel="preload"
href="/_next/static/chunks/framework.94bc9fd9a7de53a90996.js"
as="script"
/>
<link
rel="preload"
href="/_next/static/chunks/commons.6419ced117edf62014da.js"
as="script"
/>
<link
rel="preload"
href="/_next/static/runtime/main-2ba45c6c0e61dfa5f796.js"
as="script"
/>
</head>
<body>
<div id="__next">
<div style="margin:20px;padding:20px;border:1px solid #DDD">
<h1>Error Pages</h1>
<ul>
<li><a href="/errorPage/1/">test a</a></li>
<li><a href="/errorPage/2/">test 2</a></li>
</ul>
</div>
</div>
<script
nomodule=""
src="/_next/static/runtime/polyfills-2889d9d9fcf08314dd3a.js"
></script>
<script
async=""
data-next-page="/"
src="/_next/static/UkokJ2QynwMCza2ya8Vuz/pages/index.js"
></script>
<script
async=""
data-next-page="/_app"
src="/_next/static/UkokJ2QynwMCza2ya8Vuz/pages/_app.js"
></script>
<script
src="/_next/static/runtime/webpack-91b117697e716c22a78b.js"
async=""
></script>
<script
src="/_next/static/chunks/framework.94bc9fd9a7de53a90996.js"
async=""
></script>
<script
src="/_next/static/chunks/commons.6419ced117edf62014da.js"
async=""
></script>
<script
src="/_next/static/runtime/main-2ba45c6c0e61dfa5f796.js"
async=""
></script>
<script
src="/_next/static/UkokJ2QynwMCza2ya8Vuz/_buildManifest.js"
async=""
></script>
</body>
</html>
Is there a way to tell next to include this js files inline?
What I tried:
I am trying to use HtmlWebpackPlugin and HtmlWebpackInlineSourcePlugin and updated next.config.js like this:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin')
module.exports = {
exportTrailingSlash: true,
exportPathMap: async function () {
const paths = {
'/': { page: '/' }
}
const errorPages = [
{ id: 1, name: 404', lang: 'en' },
{ id: 2, name: '500', lang: 'en' }
]
errorPages.forEach(errorPage => {
paths[`/errorPage/${errorPage.id}`] = {
page: '/errorPage/[id]',
query: { id: errorPage.id }
}
})
return paths
},
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
config.plugins.push(new webpack.IgnorePlugin(/\/__tests__\//))
config.plugins.push(
new HtmlWebpackPlugin({
inlineSource: '.(js|css)$' // embed all javascript and css inline
})
)
config.plugins.push(new HtmlWebpackInlineSourcePlugin())
return config
}
}
it doesn't transform the resources into the inline format and keeps linking them. Is there a way to achieve the desired result with any other webpack addition or is the config wrong?
thanks in advance!
EDIT: this is my project.json dependency section:
"dependencies": {
"isomorphic-unfetch": "^3.0.0",
"next": "latest",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"html-webpack-inline-source-plugin": "0.0.10",
"html-webpack-plugin": "^3.2.0"
}
Solution 1:[1]
What I ended up doing is using a StaticDocument
instead of the default Document
(when in the production environment). Then my StaticDocument is used with CustomHead
during export. In there, all link preloads are removed. Like this, no link tag will be rendered in the <head>
of the final exported HTML page.
~/pages/_document.js
import Document, { Main, Head } from 'next/document'
class CustomHead extends Head {
render () {
const res = super.render()
function transform (node) {
// remove all link preloads
if (
node &&
node.type === 'link' &&
node.props &&
node.props.rel === 'preload'
) {
return null
}
if (node && node.props && node.props.children) {
return {
...node,
props: {
...node.props,
children: Array.isArray(node.props.children)
? node.props.children.map(transform)
: transform(node.props.children)
}
}
}
if (Array.isArray(node)) {
return node.map(transform)
}
return node
}
return transform(res)
}
}
class StaticDocument extends Document {
render () {
return (
<html>
<CustomHead />
<body>
<Main />
</body>
</html>
)
}
}
export default process.env.NODE_ENV === 'production'
? StaticDocument
: Document
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | G43beli |