-
Notifications
You must be signed in to change notification settings - Fork 27.6k
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
Allow disabling runtime JS in production for certain pages (experimental) #11949
Conversation
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
Landing this as experimental, I can't spend tons of time on adding all the needed changes to make it work in development right now so the DX won't be what you'd expect. e.g. if you use If someone wants to work on this feature (with guidance from me) please let me know: https://twitter.com/timneutkens, dm's are open. |
How do you opt-in a page to use this in latest canary? Does one also additionally need to configure something in |
|
This configuration at which place, we need to add in next.config.js / certain page ? |
It's a per-page configuration option. |
ok,this configuration will work on next build /not? |
Looks like the This can be a fairly large chunk of html, and I can't think of a good reason to include it in a completely static page. Am I missing something? |
It's there mostly because users might need certain properties from getStaticProps/getServerSideProps which are passed through there. |
I feel that defeats the purpose of trying to create very lean pages. If the user needs anything specific from It should at least be configurable, since there is not easy way to get rid of that fairly large chunk of markup that will most likely be unneeded in most |
this configuration
should work for Static/Server/SSG page,not for specific server page. |
@sai1139 I'm not sure what you mean exactly - if you want to opt-out a page from including Next.js runtime JS , you configure that page to exclude it: // in pages/index.js
export const config = {
unstable_runtimeJS: false
}
export default () => <h1>My page</h1> And that specific page's markup will not include the Making this a per-page config It actually ensures that it doesn't break other pages |
Feel free to open a PR to change it, as said this was just an initial implementation. |
Not sure what you mean. You can read the details of this PR here: #11949 (comment) |
Happy to take a stab at this. Would you prefer I just remove it or make it configurable? If configurable, does |
Removing it when |
this configuration is not working in developement and production |
@sai1139 As mentioned in the description - this only work for statically generated pages, and only in production mode. It doesn't work in dev mode so that hot module reload still works |
@TxHawks thanks for information, but i have done sample example and tested in production mode. this configuration is working you, can you share me in git url, i will get to know. |
And your pages are statically generated? I works fine for me. A simple reproduction repository could help figure out what the issue is |
@TxHawks can you share me in git url, i will get to know. |
Do note that it's not required to statically generate the page, if you use SSR it works too 🙏 It works fine on my personal website btw: https://timn.tech/ https://github.com/timneutkens/timn.tech/blob/master/pages/index.tsx#L4-L6 |
@timneutkens thanks for the information.if other information, i will let you know. |
Is |
Yes, it's currently only used for a few options though. E.g. to enable AMP support or to disable body parsing on API routes. |
I see; this is the first feature for Next where I've seen this pop up; the timing of it is incredible as I was needing this! |
@timneutkens How would I go about testing that my changes actually work? It actually required a very small change to - 692 {staticMarkup ? null : (
+ 692 {(staticMarkup || disableRuntimeJS) ? null : (
693 <script
694 id="__NEXT_DATA__"
695 type="application/json" |
@TxHawks what about using |
We have production tests too, I didn’t add tests for this behavior yet as it was just a proof of concept. You can copy tests/integration/production into a “disable-js” directory and test the changes there, the tests are pretty straight-forward if you look into the directory 👍 |
We use the “wd” package in the Next.js test suite as we test multiple browsers (IE11, safari, Firefox, chrome) hence why puppeteer is not used |
@timneutkens Pull request submitted in #12406, including initial tests |
Nice! This is how I was doing this before (+ removing As you say, this always felt wrong because it was overriding internals. I'm excited to see where this leads. |
* Remove tsconfig-paths-webpack-plugin since Next.js added native support for tsconfig.json baseUrl (https://nextjs.org/blog/next-9-4#absolute-imports-and-aliases) * Replace hacky _document.tsx overrides to remove client-side JS with config.unstable_runtimeJS (vercel/next.js#11949)
@timneutkens Thanks for making this. It is exactly what i was looking for. |
@timneutkens Above you stated the following:
Is there an example of this in the Next.js examples? I'm under the impression that one would need to:
Thanks Tim for all the work you've put into this. |
As this is experimental and not complete (as per my initial PR message) so we're not adding examples for it in the examples directory in case the implementation changes. However as said:
I only built the part where JavaScript is deleted, not the part where you can add it back with compilation. Currently you can add a script tag from e.g. the public directory and that works. It'd be a good iteration of the feature to work on a way to get a compiled script though. However this does make things more complex. For example the webpack runtime would have to be shipped to the browser. Feel free to reach out if you want to work on that. |
Hello @timneutkens I just wanted to chip in my thoughts regarding the readiness for stable release of this feature. As you say, it would be a good iteration of the feature to get a compiled script though. But that's maybe a nice to have for a next version, or iteration as you say. For a first version, it would be "perfect" just to remove javascript. And if any is needed, add those scripts via the public directory, as one already can. Yes, those would need to be compiled separately, but I think that's totally fine. For my use case, a content heavy blog site, I really love nextjs and react to build my pages. But it is very content heavy without much "interaction". So I thought having a full blown react app on the front-end might not be necessary and maybe just add one or two lightweight preact 'widgets' at pin-point locations with preact-habitat. Since I can reuse components done in the nextjs environment, there's not much extra work and I don't mind having to compile them separately. Since I am using a different framework, I probably would have to anyway. What do you think about going stable with a minimum viable product and "just" focussing on removing runtimeJs? |
This does not match our long-term vision for the feature (as described in my PR message) and would cause breaking changes (or having to maintain this feature as-is forever), both cases are losses as it would mean we then have to deprecate/replace existing stuff and cause overall churn that is not needed. Hence why I said in my initial message:
The initial PR was just to show what parts have to be touched and allow users to try it out if they really want to get rid of JS |
Thanks for your feedback Tim. |
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/timneutkensDo note that in this implementation it means no runtime JavaScript will be executed so you won't be able to use React hooks, event listeners etc without injecting custom
<script>
tags into the rendered html (eg throughnext/head
) for pages that useunstable_runtimeJS: false