Skip to content

Issues migrating from babel-plugin-css-modules-transform with dart-sass #36

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

Closed
kapowaz opened this issue Feb 2, 2023 · 8 comments
Closed

Comments

@kapowaz
Copy link

kapowaz commented Feb 2, 2023

I’m migrating an older project which uses babel-plugin-css-modules-transform, and after some research I discovered you now recommend your babel-plugin-react-css-modules babel plugin as an alternative approach, as the previous packages are all abandoned/outdated.

My project setup involves React + TypeScript with SCSS. The package is published in two parts: an NPM package containing babelified JS files representing React components as CommonJS, plus a manifest file, and a set of static assets (a single minified CSS file, fonts etc.) which are published to a CDN.

The publish pipeline also runs in two parts: first it uses webpack to compile the Sass into the stylesheet published on the CDN, and then it uses babel to compile the respective JS files. As part of this process I have always used css-modules-transform to add the var styles = { ... } object to each component. So, assuming I start out with:

// styles.scss
.someClassName {
  color: red;
}
/* MyComponent.tsx */
import styles from './styles.scss';

export const MyComponent = () => <div className={styles.someClassName}>hello world</div>;

I would expect to get something like this output:

/* application.css */
.kpwz-fc6e99e5512e50ed{color:red}
/* MyComponent.js */
var styles = {
  "someClassName": "kpwz-fc6e99e5512e50ed"
};

const MyComponent = () => {
  return /*#__PURE__*/(0, _jsxRuntime.jsx)('div', {
    className: styles.someClassName,
  });
};

exports.MyComponent = MyComponent;

All of the above has been working fine with my existing setup, and I’m using it successfully on a couple of sites (e.g. here). But a bunch of the internals were a little outdated, so I’ve started the work to gradually upgrade from e.g. webpack 4 to 5, babel 6 to 7, node 14 to 16 (so far).

However, the upgrade from node-sass to dart-sass has blocked all of this: for whatever reason the ident name generated by generateScopedName is different between the stylesheets emitted by webpack and the styles = { ... } block appended to the component by babel-plugin-css-modules-transform. I’ve exhausted all the paths I feel I can explore (for my level of knowledge of babel, at least) to try and understand why this is happening, but as best as I can tell, something about the different way that the ident name is being determined from babel-plugin-css-modules-transform compared to webpack (with css-loader, postcss-loader and sass-loader) is resulting in these different classnames.

Circling back to the start, I discovered your package and it sounds like it should solve the problem I have, but I’m not able to get it to output the var styles = { ... } block in the published component, despite following what the readme suggests. This is the config I have in my .babelrc:

"plugins": [
  "@babel/plugin-proposal-class-properties",
  "add-react-displayname",
  [
    "@dr.pogodin/react-css-modules",
    {
      "generateScopedName": "kpwz-[contenthash:16]",
      "replaceImport": true
    }
  ]
]

For completeness, here is the equivalent section of my webpack.config.js:

{
  test: /\.scss$/,
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
    },
    {
      loader: 'css-loader',
      options: {
        modules: { localIdentName: 'kpwz-[contenthash:16]' },
        sourceMap: false,
      },
    },
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [cssnano()],
        },
      },
    },
    {
      loader: 'sass-loader',
      options: {
        implementation: require('sass'),
      },
    },
  ],
},

What am I missing from my config to get the desired output?

@kapowaz
Copy link
Author

kapowaz commented Feb 2, 2023

I’ve since found your comment here and realised this is the exact root cause of my issue. To test it, I followed your steps here to update how both my webpack and babel config specify the localIdentName (with generateScopedNameFactory in my babel config, and a custom getLocalIdent in my webpack config) and suddenly my build works again, with matching classnames!

This is without even moving away from css-modules-transform; just specifying the generatedScopeName this way fixes the issue. I do still think there would be value in me moving away from the older, defunct library, so if you have the time to offer any suggestions on my issue with migrating to your @dr.pogodin/react-css-modules plugin, I’d appreciate it!

@birdofpreyru
Copy link
Owner

Hi @kapowaz!

but as best as I can tell, something about the different way that the ident name is being determined from babel-plugin-css-modules-transform compared to webpack (with css-loader, postcss-loader and sass-loader) is resulting in these different classnames

Right. There were a bunch of different changes in those modules over the last few years that altered generated classnames on multiple occasions.

I discovered your package and it sounds like it should solve the problem I have,

Correct. I believe, it does what you want.

This is the config I have in my .babelrc:

I think, the problem is that you rely on SCSS, and for this plugin to understand SCSS you should:

@kapowaz
Copy link
Author

kapowaz commented Feb 2, 2023

Hi @birdofpreyru — thanks for the swift reply! That’s encouraging that this should work the way I want it to, using your more modern plugin. I’m struggling a bit with integrating the filetypes section to my babel config though, would you be able to share a more complete example of how I should be using it? I’ve tried in the most logical place(s), but it causes babel to fail:

'dist-js-build': {
  presets: [
    ['@babel/preset-typescript', { allowNamespaces: true, allowDeclareFields: true }],
    ['@babel/preset-env'],
    [
      '@babel/preset-react',
      {
        runtime: 'automatic',
      },
    ],
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    'add-react-displayname',
    [
      '@dr.pogodin/react-css-modules',
      {
        extensions: ['.scss'],
        generateScopedName: generateScopedNameFactory('kpwz-[contenthash:16]'),
        preprocessCss: './src/loaders/sass-loader.js',
        filetypes: {
          '.scss': { syntax: 'postcss-scss' },
        },
      },
    ],
  ],
},

This is the output from babel:

$ BABEL_ENV='dist-js-build' babel src --extensions '.ts,.tsx,.js,.jsx' --out-dir dist --ignore src/index.js,src/**/examples.js,src/**/*.test.js,src/**/*.test.ts,src/**/*.test.tsx,src/test/** --quiet
[
  {
    instancePath: '',
    schemaPath: '#/additionalProperties',
    keyword: 'additionalProperties',
    params: { additionalProperty: 'extensions' },
    message: 'must NOT have additional properties'
  }
]
Error: /Users/bdarlow/Development/npm/@kapowaz/components/src/components/AbstractButton/AbstractButton.module.scss.d.ts: Invalid configuration

@birdofpreyru
Copy link
Owner

I believe, you placed it well. The error reads like it tried to parse AbstractButton.module.scss.d.ts file and failed. I guess, it probably tries to parse all files with .scss anywhere in the name, probably you can use exclude option of this plugin to explicitly ban .scss.d.ts files from the processing.

@kapowaz
Copy link
Author

kapowaz commented Feb 2, 2023

Yeah, that was my first guess too, so I deleted the .scss.d.ts file; then when I repeated the step it gave the same error about AbstractButton.stories.tsx, which doesn’t have .scss anywhere in the filename.

@birdofpreyru
Copy link
Owner

Agh... then, I guess, it struggles to handle TypeScript, and you should add Babel plugin for TypeScript compilation into plain JavaScript prior to this one.

@kapowaz
Copy link
Author

kapowaz commented Feb 2, 2023

I need to focus on something else so I’ll revisit this and try that in a little while! Thanks for the help!

@kapowaz
Copy link
Author

kapowaz commented Feb 3, 2023

Just to give you a quick update: I’ve decided in the interim to fork css-modules-transform with updated dependencies, and I’m including your solution to handle the localIdentName differences. Longterm I’ll look into migrating to just using your package, but for now I have something that works, so thanks for the help!

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

No branches or pull requests

2 participants