-
Notifications
You must be signed in to change notification settings - Fork 27.6k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Truly static pages without react app #5054
Comments
I think you can do that with a custom // pages/_document.js
import Document, { Main, NextScript } from 'next/document'
const pagesWithoutReact = ['/'];
export default class MyDocument extends Document {
render() {
const { __NEXT_DATA__ } = this.props;
return (
<html>
<body>
<Main />
{!pagesWithoutReact.includes(__NEXT_DATA__.pathname) ? <NextScript /> : null}
</body>
</html>
)
}
} |
@danielr18 that's not a reliable way to remove the script tags as they're still preloaded. |
Technically looks like that would do the job. Discovered Now facing another issue not directly related to next.js itself. The static page i'm trying to render is a snapshot of quite complex page currently rendered by Wordpress. If i navigate to this page directly (with full page reload) everything is smooth. But navigation using Link breaks the scripts already present on the page (there's angular, jquery and whole galaxy of other trash). Looks like something to do with scripts load order when they're added to the body dynamically. Continue with this - would rather have some neat solution in place before creating PR. |
This would be a great addition to this ecosystem. We are looking to generate a number of static landing pages as lightweight entry points into our SPA. This is the perfect solution. |
Whats the status of this? I'm needing something like this too. |
Curious about the state of this, as I'm also looking to implement something similar for statically exported error pages. |
Is there any other tool available to do this now? I too need something similar. |
I did it as danielr18 described. Create a custom |
I also did something similar to @danielr18. The problem with his example is that JavaScript files are still preloaded even though they are not needed. I extended // 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: node.props.children.map(transform),
},
};
}
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; This generates a minimal build without any JavaScript when running |
@bancek had a small issue with your solution, had to change:
To:
|
Super applying is Email templates embed in ecosystem, not as a side feature |
@askirmas can you elaborate? |
@iamstarkov In autumn |
@askirmas i meant that i dont understand you |
Example
export default ({children}) => <><Header/>{children}<Footer/></>
export default ({children}) => <>
<EmailHeader/>
<div>Dear {full_name}</div>
{children}
<EmailFooter/>
</>
export default () =><b>New Super Proposition!</b> With
There are many limitations to send |
@bancek or @TriPSs have you guys completely cut off the re-hydration this way? Have you tried to do any partial-hydration so that |
@timothyjoh yes, we've completely cut off the re-hydration. There is no JavaScript on our static pages. We use Next.js to reuse styles and React components between our React app and our static pages. On our static pages we keep the styles. Example: https://app.koofr.net/legal/privacy |
I am going to look into a way to defer hydration, so that after page load (and CPU-idle) that we would then load react and re-hydrate the links to other pages. If the user starts to interact with the page (using the search box or scrolling) hopefully this will not mess up the experience. But if they click a link to navigate away before the page is hydrated, maybe the That's my panacea that I am shooting for anyway. |
I tried the solution to remove the preload links, they are removed server side, but gets injected clientside... Whats is going on here? How can it be injected when they are removed? Anyhow, i solved it by adding
` static getInitialProps = async ({ query, reduxStore }) => {
|
Does anyone have a suggestion for how to accomplish this while retaining the CSS imports? I'm new to the platform but perusing the source for the Document component shows it's quite complex, I'm hard pressed to think that just subclassing the component to replace the render method entirely with a simple one, as proposed here by @danielr18 and others, is going to suffice. Not only for the CSS but other functionality captured there, as evidenced by others in the thread having to go further to preserve things like head tags but not include preload tags, etc. Perhaps someone here is familiar or adventurous enough to modify the Document component to accept a flag to disable the scripting/preloading behaviors while retaining those still pertinent to static pages (CSS, various head meta tags, etc)? |
Hi. `export default class CustomHead extends Head {
}` |
Can be achieved with customized react-helmet setup, see: |
@Luxiyalu that approach breaks a lot of Next.js features as suddenly Next.js can't inject anything. eg HTML properties needed for AMP, styles from css-in-js solutions, |
Fair enough, but in this case we truly don't want any file injected from head, js or css. All we want is static HTML, sans even js. The react aspect is only added for easier composition of pure HTML, nothing more, and nextjs is what makes it possible to remove js from a react page. Thanks for that, by the way! The next/head was replaced with react-helmet for customizing head, html and body attributes, and as for upgrades, can't have everything in life :) |
@Luxiyalu @timneutkens since I need the nextjs-generated CSS in my static site, I can't use any of the approaches here. What I do right now is apply a post-processing stage after exporting and before deployment. For all html files in the export folder (out/), I strip the script tags, strip the preload link tags, and then also delete everything in out/_next except the out/_next/static/css folder. The resulting file hierarchy is pushed to an s3 bucket which then serves the site statically. |
I believe what you want is Svelte. It's inspired by NextJS, and one of their main concerns is "No virtual DOM" and, overall, to move all the framework cycles into compile time, rather than runtime. |
@jerrygreen That's a cool project, but switching to a totally different framework and losing the leverage of react+webpack doesn't strike me as a good tradeoff just to get rid of unneeded script tags in the final page render. Also keep in mind I'm interested in an S3-bucket site, with no backend (not Svelte's main use case). Granted javascript-less pages are not the intended use case for React either, but, there are still some major advantages to using React even for static sites, such as declarative/reusable componentry, webpack asset and css pipeline processing, and so forth. NextJS is very close to supporting this. All NextJS needs to do is omit the script tags on export, preferably with a per-page flag (perhaps in the export path map?) In the meantime, stripping script tags in post-processing step after export is an OK workaround. |
This allows a page to be fully static (no runtime JavaScript) on a per-page basis. The initial implementation does not disable JS in development mode as we need to figure out a way to inject CSS from CSS imports / CSS modules without executing the component JS. This restriction is somewhat similar to https://www.gatsbyjs.org/packages/gatsby-plugin-no-javascript/. All things considered that plugin only has a usage of 600 downloads per week though, hence why I've made this option unstable/experimental initially as I'd like to see adoption patterns for it first. Having a built-in way to do this makes sense however as the people that do want to adopt this pattern are overriding Next.js internals currently and that'll break between versions. Related issue: vercel#5054 - Not adding `fixes` right now as this implementation needs more work. If anyone wants to work on this feel free to reach out on https://twitter.com/timneutkens
I've opened up a PR (#11949) to add initial support for this feature on a per-page basis, it still needs quite a bit of work to get the DX right, if anyone wants to work on that please reach out to me on https://twitter.com/timneutkens |
Posting my reply on the PR here so that people looking for it can see:
|
This allows a page to be fully static (no runtime JavaScript) on a per-page basis. The initial implementation does not disable JS in development mode as we need to figure out a way to inject CSS from CSS imports / CSS modules without executing the component JS. This restriction is somewhat similar to https://www.gatsbyjs.org/packages/gatsby-plugin-no-javascript/. All things considered that plugin only has a usage of 600 downloads per week though, hence why I've made this option unstable/experimental initially as I'd like to see adoption patterns for it first. Having a built-in way to do this makes sense however as the people that do want to adopt this pattern are overriding Next.js internals currently and that'll break between versions. Related issue: #5054 - Not adding `fixes` right now as this implementation needs more work. If anyone wants to work on this feel free to reach out on https://twitter.com/timneutkens
First of all: I like this feature a lot 👍. Maybe a good starting point is:
I mean you should know what are you doing with this flag. It's userlands problem when they use features like |
See above PR, it adds an unstable flag to opt-in.
Feel free to add that, but it's tricky to only show it once, it would show on every render. |
If somebody is interested, I've built a plugin that allows to add vanilla JS entry points for pages that have Note that this plugin modifies webpack configuration of Next.js. Similar as with other Next.js plugins that do this, it's possible that this plugin will break when there are updates to Next.js. I'm keeping the plugin updated so that it continues to work with new versions of Next.js. I've just updated the plugin to work with Next.js 9.5 🙂 . |
A neater way of doing this (pruning out the script tags via a custom Have some logic in a custom node and serving this for paths as necessary That also has the advantage of leaving your site completely untouched for normal paths which need javascript interactivity I am doing this for a side project I am working on and it's working nicely |
@artcg do you example of that |
Sure, I won't include all the boilerplate etc that you would include but the pattern is simply // server.js
const {createServer} = require('http');
const {parse} = require('url');
const next = require('next');
const app = next({dev: process.env.NODE_ENV !== 'production'});
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true);
if (parsedUrl.pathname === '/static_example') {
yourOwnCustomHandler(req, res);
// render your React Component to static markup here,
// add HTTP headers, and write to res, then call res.end()
} else {
handle(req, res, parsedUrl);
}
}).listen(8080, err => {
if (err) throw err;
});
}); The result is effectively your entire site is running with NextJS, except for whichever route you define which you can handle yourself It's just node so it is fully controllable :) |
This solutions makes you opt out of all Next.js features because you opt-out of using Next.js completely. Would recommend just using #11949. |
I tried that but it didn't work, and there is no documentation for it anywhere, for my case it was easier to opt out of next for that file |
Isn't the following solve this issue?
(taken from #11949) |
Only partially. See #11949 (comment) |
Having truly static pages is something I want as well. I ended up doing it post-export since I already had some hooks there, but having it natively would be nicer. I am looking forward to https://twitter.com/shaneOsbourne/status/1360708099552780293 being released :) |
My usecase is similar to those that have mentioned "email templates." Email templates really shouldn't have any JS in them at all, so having this ability would really open doors for my team. Right now I am planning on just injecting the template into an iframe to support this usecase. Here's what I'm doing: import { EmailTemplateContextUiProvider } from '@ui/contexts/email-template-context';
import React, { FC, ReactChild, ReactChildren } from 'react';
import Frame from 'react-frame-component';
export interface EmailTemplateBaseProps {
shouldRenderIframeWrapper?: boolean;
shouldRenderHtmlAndBody?: boolean;
shouldRenderNextPage?: boolean;
title?: string;
head?: ReactChildren | ReactChild;
}
export const EmailTemplateBase: FC<EmailTemplateBaseProps> = ({
children,
shouldRenderNextPage = true,
shouldRenderIframeWrapper = shouldRenderNextPage,
shouldRenderHtmlAndBody = shouldRenderIframeWrapper,
title = 'My Email Template',
}) => {
let newChildren = (
<EmailTemplateContextUiProvider>
{children}
</EmailTemplateContextUiProvider>
);
// Optionally render template inside a full HTML document, otherwise
// render the template's body only
if (shouldRenderHtmlAndBody) {
newChildren = (
<html>
<head>
<title>{title}</title>
</head>
<body>{children}</body>
</html>
);
}
// Optionally render template inside an <iframe /> to avoid any JS from Next.
// When NextJS supports fully static pages, we can rethink this: https://github.com/vercel/next.js/issues/5054#issuecomment-805829676
if (shouldRenderIframeWrapper) {
newChildren = (
<Frame
style={{
width: '100%',
height: '100%',
border: 0,
flexGrow: 1,
padding: 0,
margin: 0,
}}
>
{children}
</Frame>
);
}
return newChildren;
}; |
Just figured I need some embeddable component for an iframe for one page, pretty much like Twitter embeddable card or something. I would like to have some js in there though, so react hooks etc, - I want that, but I wanna disable all the nextjs features like any kind of preloading, routing, etc. Is it possible to disable all that just for one page? Or should I create-next-app inside another nextjs app to isolate this little page and it's the only way currently? |
In my case, I'm still using the workaround that @bancek proposed above because the The problem I recently encountered is when using the new Image component, that the |
I think this is worth the effort. I was tempted to use astro just because of this. But i prefer Next by far so im kinda stuck with either full React or only basic self made html css build tools with webpack. I even tried Hugo but it was way overcomplicated. |
Now with Next.js 12 and the alpha integration with Server Components, will this issue have a proper solution?
I was waiting for the React Server Components (RSC) to land hoping that they would trivially solve this issue since they could run once during compile time, and then the runtime could just include the client component along with the static version of the server components embedded (if needed at all). However, the Server Components alpha documentation, https://nextjs.org/docs/advanced-features/react-18#unsupported-nextjs-apis, mentions:
So this feels that they are only usable when you actually have a server running, and not integrated with Is this something due to being Thanks for all the amazing work so far! |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Feature request
Is your feature request related to a problem? Please describe.
We want some static pages to be as lightweight as possible and we're fine with full page reloads navigating out of them if we can chop off extra 200Kb.
Describe the solution you'd like
Add an option to path map in next.config.js to indicate this specific page doesn't need to include react app and can operate as plain HTML page.
React app is only removed in case the flag is set to
true
explicitly.Looks like it should be enough to just make
files
content empty there if option is set. https://github.com/zeit/next.js/blob/canary/server/render.js#L100For the simple example from tutorial setting up
As a result
/out
would be populated withThis way index page is going to be very lightweight, with a tradeoff of full page reload navigating to /about. While /about would load the app, so navigation back to / would be handled on the client-side.
Describe alternatives you've considered
Static site generators :) But we need way more than just static pages and next.js fits us best except for this tiny quirk.
Additional context
Happy to implement that, just wanted to make sure this is not something going against the roadmap for next.js. Or if it's something already available, but hidden. I'm new to the library, only playing around for the second day.
The text was updated successfully, but these errors were encountered: