Skip to content
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

[BUG] Generated CSS modules class names are deleted from the HTML on production builds with optimize #3243

Open
4 tasks done
jfranciscosousa opened this issue Apr 30, 2021 · 11 comments
Labels
bug Something isn't working css-modules

Comments

@jfranciscosousa
Copy link
Contributor

jfranciscosousa commented Apr 30, 2021

Bug Report Quick Checklist

  • I am on the latest version of Snowpack & all plugins.
  • yarn 1.22.5
  • Ubuntu 20
  • I run Snowpack on Node.js v14+

Describe the bug

When using either @snowpack/plugin-webpack or the optimize config, all class names from CSS modules get removed from the markup.

Example markup from the project where this happens:
image

To Reproduce

  1. npm init snowpack-app --template @snowpack/app-template-react
  2. Setup the webpack plugin or optimize
  3. snowpack build
  4. Inspect the HTML output or serve the output folder
  5. Check that the class names are not there.

Expected behavior

For the class names to appear. https://github.com/finiam/phoenix_starter I have a starter repo (elixir + react) that is stuck on 3.3.2 and it works there. But from 3.3.3 onwards it doesn't.

On that project, with the 3.3.2 version, class names are generated correctly:
image

@fgblomqvist
Copy link

Probably this PR then: #3170
I know @drwpow has been doing a lot of work around this so hopefully it's not too bad to figure out.

@fgblomqvist
Copy link

Also, did you try the latest version? 3.3.6 or 3.3.7? Some fixes went in right before you posted this.

@drwpow
Copy link
Collaborator

drwpow commented May 1, 2021

I believe this is a duplicate of #2998, and it’s a current limitation of esbuild, which does not support CSS Modules.

Open to suggestions on temporary workarounds!

@fgblomqvist
Copy link

I'm pretty sure there must be some kind of regression in there since he says it works with the webpack plugin in 3.3.2 😅. But yes, the fact that it doesn't work with the built-in optimizer is to be expected.

@jfranciscosousa
Copy link
Contributor Author

This also happens when not using the optimize config and using @snowpack/plugin-webpack instead (with optimize disabled completely)! Also tested with both 3.3.6 and 3.3.7 and no dice. Works normally if not using those optimization strategies.

@ChristiaanScheermeijer
Copy link

We are running into the same problem with the optimization strategy (expected) and @snowpack/plugin-webpack plugin using the latest snowpack version (3.3.7). I've tried multiple versions from 3.3.2 without success.

Looking at the build output, it seems that the JSON keys are being renamed. While the JSX output still uses the original properties.

The CSS does contain the correct classNames, but it also includes the @use keywords in the output.

Source:

import styles from './Auth.module.scss';

const Auth = () => {
  return (
    <Layout>
      <div className={styles.Auth} />
    </Layout>
  );
};

Build output:

@use "../../styles/variables";
@use "../../styles/theme";
._22ImGiStC_zj9-aVAVSHUL{display:flex;justify-content:center;align-items:center;height:100vh}
se={_Auth_13g8k_1:"_22ImGiStC_zj9-aVAVSHUL"}
u.b.createElement(B,null,u.b.createElement("div",{className:se.Auth}))

@chapman-cc
Copy link

chapman-cc commented May 23, 2021

Came here with same issue
I'm using @snowpack/plugin-webpack for bundling
I can see the css-loader works correctly, extracting the

\\ App.module.css 
.yellowText { color: yellow; }

styles into the bundled css file, but in the js file, it became like this

function (e, t, r) {
  "use strict";
  r.r(t);
  var n = r(0),
    o = (n.c.useEffect, n.c.useState, r(1)),
    u = { _yellowText_1crdi_1: "Fo01xQr36oH9LiM0VHSA7" };   <============ CHANGED
  var c = function () {
    return n.c.createElement(
      "h1",
      { className: u.yellowText },  <============ UNCHANGED
      "Hello World"
     );
   };
   o.a.render(
     n.c.createElement(n.c.StrictMode, null, n.c.createElement(c, null)),
     document.getElementById("root")
   );
 },

here's how to reproduce the problem https://github.com/ChapmanCheng/snowpack_webpack_build_error

@chapman-cc
Copy link

chapman-cc commented May 23, 2021

if seems like it's not a problem with CSS loaders, but a problem when parsing JS files, the parser cannot correctly resolve the component, e.g.

// in my /build/dist/App.js component (built by snowpack, not webpack)
import React, {useState, useEffect} from "../_snowpack/pkg/react.js";
import styles from "./App.module.css.proxy.js";
function App() {
 return /* @__PURE__ */ React.createElement("h1", {
   className: styles.yellowText
 }, "Hello World");
}
export default App;

though the plugin-webpack was able to resolve the *.proxy.js file with node_modules/@snowpack/plugin-webpack/plugins/proxy-import-resolve.js, hence the yellowText css property appeared in the final css file

however, the final js file is still showing className: styles.yellowText
which means it didn't retrieve the exported value from the ./App.module/css.proxy.js and replaced the current one

hope this helps a bit more

@ChristiaanScheermeijer
Copy link

It looks like it is creating a valid build when removing the proxy-import-resolve loader actually. I'm not sure what the impact is though.

The following config removes the loader from the Webpack config:

    ['@snowpack/plugin-webpack', {
      extendConfig: (config) => {
        const babelRule = config.module.rules.find((rule) => 
          rule && rule.use && rule.use.find((use) => use && use.loader && use.loader.includes('babel-loader')));

        if (babelRule) {
          babelRule.use = babelRule.use.filter(use => !use.loader.includes('proxy-import-resolve'));
        }

        return config;
      },
    }],

@monken
Copy link

monken commented Jun 3, 2021

I was just about to post the same thing. I even removed all rules from the webpack config which creates a working bundle. The main drawback is that there are no CSS files generated which is not ideal performance wise.

['@snowpack/plugin-webpack',
            {
                extendConfig: (config) => {
                    config.module.rules = [];
                    return config;
                },
            }]

@ChristiaanScheermeijer
Copy link

I've debugged the problem even further and I found the cause of the issue.

The problem is that after the Snowpack build, CSS modules are being generated with unique localIdentNames. However, the original properties are being preserved and mapped by the proxy json object.

When running Webpack optimize, the *.module.css.proxy.js imports are being rewritten to *.module.css. But this will not work since the css-loader now uses an already generated CSS file with local scope selectors.

The following suggestions might fix this problem.

  1. Disable the postCssModules processor when running a build with optimize

https://github.com/snowpackjs/snowpack/blob/cd6ec781af93f8ed34a7b93b94318eeb3f3054ce/snowpack/src/build/import-css.ts#L17-L22

  1. Set the postCssModules scopeBehavior to global when running build with optimize.

  2. Somehow use the original CSS Modules file in the Webpack build instead of the already processed file.

However, I don't know the impact of these changes.

I did found a temporary solution. The following Webpack loader strips the postCssModules uniqueness from the selectors in all *.modules.css files.

scripts/webpack/css-modules-fix.js

module.exports = function cssModulesFix(source) {
  return source.replace(/_(\w+)_[\w\d]{5}_\d+/g, function(fullMatch, originalSelector) {
    return originalSelector;
  });
};

snowpack.config.js

['@snowpack/plugin-webpack', {
      extendConfig: (config) => {
        const cssModulesRule = config.module.rules.find((rule) =>
          rule && rule.use && rule.use.find((use) => use && use.loader && use.loader.includes('css-loader') && use.options && use.options.modules));

        if (cssModulesRule) {
          cssModulesRule.use.unshift({
            loader:  require.resolve('./scripts/webpack/css-modules-fix.js'),
          });
        }

        return config;
      },
    }],

@monken this fix does create a single CSS file. You must re-enable the Snowpack loaders as well.

@drwpow drwpow added bug Something isn't working css-modules labels Jun 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working css-modules
Projects
None yet
Development

No branches or pull requests

6 participants