Skip to content

feat: generate theme.json during dev mode using in-memory CSS#15

Closed
eavonius wants to merge 2 commits intoroots:mainfrom
eavonius:feat/theme-json-dev-support
Closed

feat: generate theme.json during dev mode using in-memory CSS#15
eavonius wants to merge 2 commits intoroots:mainfrom
eavonius:feat/theme-json-dev-support

Conversation

@eavonius
Copy link

This PR adds support for generating theme.json during development.

  • Generates theme.json during vite dev.
  • Resolves source css file path relative to resources/css during dev and public/build during a build.
  • Uses the in-memory compiled css file (using hashed filename like app-*.css) during a build.
  • Strips off query "?direct" from resolved path to css file when run during dev.
  • Graceful error handling and clear warnings if CSS or Tailwind config is missing.

Tested with:

  • Sage theme integration
  • Both dev and production builds
  • File watching and full reloads on CSS changes

- Enables writing theme.json to disk when running Vite in dev mode
- Extracts CSS from the in-memory transform hook instead of relying on output files
- Writes to public/build/assets for compatibility with Sage
- Still generates theme.json during build
- Adds support for hashed CSS filenames when resolving in build
@eavonius
Copy link
Author

A complication I ran into, is that as soon as build/assets/theme.json exists (once running vite dev with this PR), it appears that when this code runs in the admin_head hook in setup.php for the sage theme:

$dependencies = json_decode(Vite::content('editor.deps.json'));

It finds the build directory there - and thinks this is a prod build. This errors out since it can't find the editor deps.

I didn't realize this was a problem until I tried to hop into the admin side of the site once the "built" theme.json exists. So I'm not sure what to do next.

@eavonius
Copy link
Author

I was able to get this to work. It would require users add a line to setup.php to check that the wordpress environment is anything other than "development" to work though (this is the approach I took at least):

add_filter('admin_head', function () {
    if (! get_current_screen()?->is_block_editor()) {
        return;
    }

    if (defined("WP_ENV") && WP_ENV !== 'development') {
        $dependencies = json_decode(Vite::content('editor.deps.json'));

        foreach ($dependencies as $dependency) {
            if (! wp_script_is($dependency)) {
                wp_enqueue_script($dependency);
            }
        }
    }

    echo Vite::withEntryPoints([
        'resources/js/editor.js',
    ])->toHtml();
});

@retlehs
Copy link
Member

retlehs commented Mar 12, 2026

Thanks for putting this together and for working through the editor.deps.json edge case

We've been working on an alternative implementation that takes a different approach: no new dependencies, no hardcoded paths, debounced atomic writes, and startup generation via transformRequest instead of reading raw CSS from disk. More details: #36

Thanks again

@retlehs retlehs closed this Mar 12, 2026
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.

2 participants