Skip to content

Prevent non-module SCSS/CSS imports in JS/TS files #76744

Description

@mirka

What problem does this address?

@wordpress/wp-build inlines all imported stylesheets into the JS bundle as runtime-injected <style> elements (with data-wp-hash deduplication). This means that if someone adds import './style.scss' in a JS file, it silently "works" at runtime, making it easy to miss that this is the wrong pattern.

In most packages, stylesheets should be imported through the package's root-level style.scss, not directly in JS. Importing in JS bypasses the standard stylesheet pipeline and causes the styles to be injected at runtime via document.head.appendChild. This has several problems:

  • Redundancy. If the stylesheet is already in the root style.scss chain, it gets loaded twice.
  • No RTL processing. Most packages rely on the build-time RTL transformation to generate -rtl.css stylesheets. Runtime-injected styles bypass this entirely, so any directional styles (margins, paddings, borders, etc.) will be broken in RTL locales.

I found three existing cases of this:

  • packages/block-editor/src/components/block-visibility/modal.js imports ./style.scss. This is redundant because the same file is already in the root packages/block-editor/src/style.scss.
  • packages/editor/src/components/collaborators-presence/index.tsx imports ./styles/collaborators-presence.scss, and list.tsx imports ./styles/collaborators-list.scss. These are not in the root stylesheet at all, so they're only loaded through the runtime injection.

What is your proposed solution?

  • Fix the existing cases. Remove the SCSS imports from the JS/TS files above. For the collaborators-presence stylesheets, also add them to packages/editor/src/style.scss.
  • Add a lint rule to prevent importing non-module .scss/.css files in JS/TS files. This should flag side-effect-only imports like import './style.scss' while allowing CSS module imports that have a binding (e.g., import styles from './style.module.scss').
  • Consider restricting wp-build inline injection to CSS modules only. Currently the compileInlineStyle transform in wp-build processes all .css/.scss imports the same way. If it only applied the runtime injection to .module.css/.module.scss files, developers would notice that the styles are missing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    [Type] Code QualityIssues or PRs that relate to code quality

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions