Skip to content

feat: generate script text at build time - #354

Open
dario-piotrowicz wants to merge 1 commit into
pacocoursey:mainfrom
dario-piotrowicz:dario/script-template-text
Open

feat: generate script text at build time#354
dario-piotrowicz wants to merge 1 commit into
pacocoursey:mainfrom
dario-piotrowicz:dario/script-template-text

Conversation

@dario-piotrowicz

Copy link
Copy Markdown

Fixes #349

const systemThemes = ['light', 'dark']

function updateDOM(theme: string) {
function updateDOM(theme) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: if there is a concern about loosing typesafety here this solution can be improved by either using jsdoc type comments here or adding a custom esbuild loader to the tsup config,

@eposha

eposha commented Apr 24, 2025

Copy link
Copy Markdown

Is it possible to review and merge?

@vicb

vicb commented Apr 28, 2025

Copy link
Copy Markdown

@pacocoursey The PR would help with the Cloudflare adapter for OpenNext - is there anything missing from the PR before it can be merged?
🙏

@pacocoursey

pacocoursey commented May 31, 2025

Copy link
Copy Markdown
Owner

Sorry, I'm late to this PR. It looks important to fix.

@dario-piotrowicz @vicb Can you share more details on the root issue here? The problem is calling .toString() on a Function instance in order to print its code?

The reason this is useful is that the code for the inline script (currently script.ts) is transpiled/minified alongside the rest of next-themes, meaning we inject cleaner/faster/production code into pages instead of the raw script.

// script.ts => 
var I = (e, t, n, l, r, a, u, h) => {
  // …vanilla JS script contents…
};

In your version, the entire script is un-minified and raw.

var L=`(
  attribute,
  storageKey,
  defaultTheme,
  forcedTheme,
  themes,
  value,
  enableSystem,
  enableColorScheme
) => ...

This is why I currently use script.toString().

@vicb

vicb commented May 31, 2025

Copy link
Copy Markdown

The problem we have is when the next-themes code is the server code.

OpenNext uses ESBuild to bundle and minify the server code. ESBuild would minify next-themes code. As part of that it renames functions and add a call to __name(rf, "originalFnName") where rf is the renamed function.

The code is valid in the server bundle where ESBuild generates a global __name function. But running the function body on the browser where __name is undefined crashes.

Providing the code as a string would prevent it to be modified during the server build step.

I think that the solution would be for this PR to minify the code.

@trm217

trm217 commented May 31, 2025

Copy link
Copy Markdown
Collaborator

Why not implement this as an option rather than it being the default behavior?

@vicb

vicb commented May 31, 2025

Copy link
Copy Markdown

Why not implement this as an option rather than it being the default behavior?

It could certainly be an option.

That being said what would be the use case for keeping the current behavior if the code is available as a string in it minified version?

IMO having an option for the string to be minified or not could be more helpful?

@dario-piotrowicz

Copy link
Copy Markdown
Author

Hi @pacocoursey thanks for you comment, no worries for the late review, better late than never 🫶

Is the minification the only concern you have with this solution? Would you be ok if the built-time generated script would be minified?

PS: regarding @trm217 suggestion, sorry but I personally am not a fan of adding an option for this, as I think that this is more of an implementation detail than something the user should actually be aware/concerned of, or am I missing something? 🤔

@trm217

trm217 commented Jun 1, 2025

Copy link
Copy Markdown
Collaborator

@dario-piotrowicz I'd argue the simplest solution should be the default case. All other advanced use cases should be able to be solved with an extendible API. Not the other way arround. I agree that it's an implementstion detail. But as paco mentioned, there are benefits to the current solution.

@dario-piotrowicz

Copy link
Copy Markdown
Author

But as paco mentioned, there are benefits to the current solution.

Could you clarify that benefits there are to the current solution? because my understanding here is that the only benefit is the minification of the code and as I asked in my previous comment I think that we can just include that in the built-time generation of the script, assuming that both solutions include the script minification, what other benefits would come from the runtime generation of the script?

@mnove

mnove commented Jun 19, 2025

Copy link
Copy Markdown

I think this is causing me some next-theme issues when deploying a nextjs app with Cloudflare adapter for OpenNext (v1)

The temp fixed I found is to update your wrangler.jsonc and add keep_names: false.
See: https://opennext.js.org/cloudflare/howtos/keep_names#how-to-fix-such-issues

I haven't tested yet if this change causes other issues.

@man-bug

man-bug commented Sep 6, 2025

Copy link
Copy Markdown

+1

keep_names: false is a fine workaround for now, but if a fix for the library is available, that feels like the intuitive choice.

This does not have to be default behavior; an optional prop (similar to the existing fix for Cloudflare Rocket Loader) would be awesome.

Was hinted at before with vicb's comment on 'crashes,' but to be clear, this issue seems to cause silent SSR failure, not just a light mode flash!

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request]: generate the script string at build time

7 participants