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

cssModuleHook option is not working #333

Closed
caoanhhao opened this issue May 23, 2017 · 27 comments
Closed

cssModuleHook option is not working #333

caoanhhao opened this issue May 23, 2017 · 27 comments

Comments

@caoanhhao
Copy link

cssModuleHook option is not working.
"base.css"

$blue: #2196f3;
.test {
   color: $blue;
}

"server/index.js"

const postCssSimpleVars = require("postcss-simple-vars")`
support.load({
  cssModuleHook: {
    generateScopedName: 'local',
    use: [postCssSimpleVars]
  }
}).then(() => {
  SSRCaching.enableCaching();
  SSRCaching.setCachingConfig(cacheConfig);
  return electrodeServer(electrodeConfippet.config, [staticPathsDecor()])
})

=> "main.style.css"

$blue: #2196f3;
.base__test___2FzsK {
   color: $blue;
}

i expect file "main.style.css"

.test {
   color: #2196f3;
}

How can i do that? ( test in "samples/universal-react-node" )
Thank you.

@caoanhhao
Copy link
Author

caoanhhao commented May 24, 2017

i can do that.
i override "extract-style" webpack partial, use "sass-loader". see #155 #222 #226 webpack-config-composer
=> i can import scss.
Thank all

import style from '../../styles/base.scss'

file: <app>/src/server/index.js

require.extensions[".css",".scss"] = () => {
  return;
};

file: <app>/webpack.config.dev.js

module.exports = function(composer, options, compose) {
  const customProfile = {
    partials: {
      "_extract-style": { enable: false },
      "custom-extract-style": {
        order: 2101
      }
    }
  }

  composer.addPartials( {
    "custom-extract-style": {
      config: require('./config/webpack/partial/custom-extract-style')()
    }
  })

  return composer.compose({}, [].concat(options.profileNames).concat([customProfile]))
}

file: <app>/config/webpack/partial/custom-extract-style.js

"use strict";

const archetype = require("electrode-archetype-react-app/config/archetype");
const Path = require("path");
const webpack = require("webpack");
const glob = require("glob");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CSSSplitPlugin = require("css-split-webpack-plugin").default;

const atImport = require("postcss-import");
const cssnext = require("postcss-cssnext");

const autoprefixer = require("autoprefixer-stylus");
const cssLoader = require.resolve("css-loader");
const styleLoader = require.resolve("style-loader");
const stylusLoader = require.resolve("stylus-relative-loader");
const postcssLoader = require.resolve("postcss-loader");

const AppMode = archetype.AppMode;

/**
 * [cssModuleSupport By default, this archetype assumes you are using CSS-Modules + CSS-Next]
 *
 * Stylus is also supported for which the following cases can occur.
 *
 * case 1: *only* *.css exists => CSS-Modules + CSS-Next
 * case 2: *only* *.styl exists => stylus
 * case 3: *both* *.css & *.styl exists => CSS-Modules + CSS-Next takes priority
 *          with a warning message
 * case 4: *none* *.css & *.styl exists => CSS-Modules + CSS-Next takes priority
 * case 5: *cssModuleStylusSupport* config is true => Use both Stylus and CSS Modules
 */

const cssNextExists = (glob.sync(Path.resolve(AppMode.src.client, "**", "*.css")).length > 0);
const stylusExists = (glob.sync(Path.resolve(AppMode.src.client, "**", "*.styl")).length > 0);

// By default, this archetype assumes you are using CSS-Modules + CSS-Next
const cssModuleSupport = !stylusExists && cssNextExists;

module.exports = function () {
  const cssModuleStylusSupport = archetype.webpack.cssModuleStylusSupport;
  const stylusQuery = cssLoader + "?-autoprefixer!" + stylusLoader;
  const cssLoaderOptions = "?modules&localIdentName=[name]__[local]__[hash:base64:5]&-autoprefixer";
  const cssQuery = cssLoader + cssLoaderOptions + "!" + postcssLoader;
  const cssStylusQuery = cssLoader + cssLoaderOptions + "!" + postcssLoader + "!" + stylusLoader;

  // By default, this archetype assumes you are using CSS-Modules + CSS-Next
  const rules = [{
    _name: "extract-css",
    test: /\.css$/,
    loader: ExtractTextPlugin.extract({ fallback: styleLoader, use: cssQuery, publicPath: "" })
  }];

  if (cssModuleStylusSupport) {
    rules.push({
      _name: "extract-css-stylus",
      test: /\.styl$/,
      use: ExtractTextPlugin.extract({ fallback: styleLoader, use: cssStylusQuery, publicPath: "" })
    });
  } else if (!cssModuleSupport) {
    rules.push({
      _name: "extract-stylus",
      test: /\.styl$/,
      use: ExtractTextPlugin.extract({ fallback: styleLoader, use: stylusQuery, publicPath: "" })
    });
  }

  if (cssModuleSupport) {
    rules.push({
      _name: "postcss",
      test: /\.scss$/,
      use: ExtractTextPlugin.extract({fallback: styleLoader, use: [{loader: cssQuery}, {loader: "sass-loader"}],publicPath: ""})
    });
  }

  return {
    module: { rules },
    plugins: [
      new ExtractTextPlugin({ filename: "[name].style.[hash].css" }),
      /*
       preserve: default: false. Keep the original unsplit file as well.
       Sometimes this is desirable if you want to target a specific browser (IE)
       with the split files and then serve the unsplit ones to everyone else.
       */
      new CSSSplitPlugin({ size: 4000, imports: true, preserve: true }),
      new webpack.LoaderOptionsPlugin({
        options: {
          context: Path.resolve(process.cwd(), "src"),
          postcss: () => {
            return cssModuleSupport ? [atImport, cssnext({
              browsers: ["last 2 versions", "ie >= 9", "> 5%"]
            })] : [];
          },
          stylus: {
            use: () => {
              return !cssModuleSupport ? [autoprefixer({
                browsers: ["last 2 versions", "ie >= 9", "> 5%"]
              })] : [];
            }
          }
        }
      })
    ]
  };
};

@dustinaleksiuk
Copy link

I did a similar fix but I don't understand why I need the change to /src/server/index.js and I don't love the require.extensions in that file. Here's my complete /webpack.config.dev.js. This works with electrode-archetype-react-app 3.x.

const _ = require('lodash');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const styleLoader = require.resolve('style-loader');
const cssLoader = require.resolve('css-loader');
const sassLoader = require.resolve('sass-loader');

module.exports = function (composer, options, compose) {
  const config = compose();

  // Remove the existing SCSS rule which for some reason is tied to the postCSS loader
  const rules = _.filter(config.module.rules,
    (item) => item.test && !_.includes(item.test.toString(), 'scss'));

  // These options come right from the existing extract-file.js partial.
  const cssLoaderOptions =
    '?modules&localIdentName=[name]__[local]___[hash:base64:5]&-autoprefixer';

  // This is based on Anooj's full file solution that he gave to Ghassan over gitter
  const sassQuery = cssLoader + cssLoaderOptions + '!' + sassLoader;

  // Put the new loader rule at the front
  rules.unshift({
    test: /\.scss$/,
    loader: ExtractTextPlugin.extract({ fallback: styleLoader, use: sassQuery, publicPath: '' })
  });

  // Replace the old list of rules with this new list
  config.module.rules = rules;

  return config;
};

@caoanhhao
Copy link
Author

@dustinaleksiuk thank you very much.
i use your code and still need the change in /src/server/index.js
if don't, the scss file will load as a javascript file.
upgrade to electrode-archetype-react-app 3.x. successful.

@dustinaleksiuk
Copy link

@caoanhhao Sorry I wasn't clear. I needed it too, but I didn't exactly understand why. I thought there would be a more elegant way to ignore SCSS on the server side.

@caoanhhao
Copy link
Author

add this line:
require.extensions[".css",".scss"] = (m, filename) => {};
isomorphic-loader will hook scss file => compile by 'sass-loader'
if don't "babel-register" will hook scss file and compile as a javascript file => compile error
isomorphic-loader

@sgsvnk
Copy link

sgsvnk commented Jul 8, 2017

@dustinaleksiuk Your snippet solved the problem for scss files. I have few css libraries imported to the app from node_modules, they are being transformed to this format - .base__test___2FzsK like how @caoanhhao mentioned. How do I avoid this?

@dustinaleksiuk
Copy link

@sgsvenkatesh I'm not sure, and I'm worried that we're going to have the same problem on our project. What I thought my solution did was add in a SCSS rule to the list of rules and kept the existing ones. If you solve this please report back and I will do the same.

@sgsvnk
Copy link

sgsvnk commented Jul 9, 2017

Yes. I found a temporary fix to this problem. You can include all your .css files in your main.scss file rather than importing it in app.jsx. That way it will be parsed as css and not js.

It will be good to have a webpack hook to avoid this problem.

@caoanhhao
Copy link
Author

@sgsvenkatesh use @dustinaleksiuk 's code.
edit this line:

// These options come right from the existing extract-file.js partial.
  const cssLoaderOptions =
    '?modules&localIdentName=[name]__[local]___[hash:base64:5]&-autoprefixer';

[name][local]_[hash:base64:5] => [local]

@jchip
Copy link
Member

jchip commented Jul 9, 2017

The styling support does need a serious overhaul and update. We use stylus internally so there's extensive custom work done to support that https://github.com/walmartlabs/stylus-relative-loader. The original dev is no longer working on these.

It detects *.css files and assumes CSS Modules. Obviously the issue is the use of CSS Modules by default and you can't turn it off. So I am thinking a quick update is to allow you to turn that off with a flag.

@sgsvnk
Copy link

sgsvnk commented Jul 9, 2017

@caoanhhao Yes, I did that and that solved for *.scss files. I'm looking for a similar solution for *.css files as well.

@jchip Yes, that should suffice. Thanks!

@SimonSomlai
Copy link

Can somebody upload a repository with a working example of getting scss to play nice with electrode? I can't seem to figure this out.

@dustinaleksiuk
Copy link

We have it working but it'll take a bit of time for me to put something that I can put in a repo. This pull request might be worth looking at: #483

@sgsvnk
Copy link

sgsvnk commented Jul 28, 2017

@SimonSomlai Here is something that worked for me - electrode-sass

@caoanhhao
Copy link
Author

@sgsvenkatesh remove sass-loader and *.scss hook for normal .css file

@sergesemashko
Copy link
Contributor

Has anyone managed to get a sass working with CSS-modules in electrode-app?

@caoanhhao
Copy link
Author

@sergesemashko yes.
Read @dustinaleksiuk 's first comment

@dan3721
Copy link

dan3721 commented Aug 29, 2017

@SimonSomlai can you help me understand the entry point. What drives into archetype/config/webpack? Is the Electrode build looking there automatically or is there a hook somewhere?

@jchip
Copy link
Member

jchip commented Aug 29, 2017

@dan3721 yes, Electrode archetype look into your app's archetype/config/webpack for your custom webpack config and load them.

@yongzhoulu
Copy link

@dustinaleksiuk thanks for your code. I use it differently in my code. keep css loader local and hash scss files. when i need to import css from 3rd party libs, it would not apply to DOM. Thanks all the way.

@yongzhoulu
Copy link

@caoanhhao can css be splitted? they run into wrong order. for vendor and app

@caoanhhao
Copy link
Author

caoanhhao commented Sep 14, 2017

@yongzhoulu
Copy link

@caoanhhao

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    {{META_TAGS}}
    {{PAGE_TITLE}}
    {{CRITICAL_CSS}}
    {{WEBAPP_HEADER_BUNDLES}}
</head>
<body>
<div class="js-content">{{SSR_CONTENT}}</div>
{{PREFETCH_BUNDLES}}
{{WEBAPP_BODY_BUNDLES}}
<script>if (window.webappStart) webappStart();</script>
<noscript>
  <h4>JavaScript is Disabled</h4>
  <p>Sorry, this webpage requires JavaScript to function correctly.</p>
  <p>Please enable JavaScript in your browser and reload the page.</p>
</noscript>
</body>
</html>

change what ?

@yongzhoulu
Copy link

@caoanhhao order in main.style.css generated by your code is strange. how controll?

@caoanhhao
Copy link
Author

caoanhhao commented Sep 14, 2017

@yongzhoulu when localIdentName=[local] add some thing like this to your html file.
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.css">

Or use css @import
https://developer.mozilla.org/en-US/docs/Web/CSS/%40import

@dan3721
Copy link

dan3721 commented Feb 6, 2018

  1. electrode-sass doesn't look to be using modules

  2. When attempting to use modules; that is importing styles like this:
    import styles from '../styles/foo.scss'

and then using them like this:
<div className={styles.test} >hello world!</div>

AND USING to make node happy:

require.extensions[".css",".scss"] = () => {
  return;
};

It "almost" works. That is the client render after hydration has the styles and they are applied as expected. However upon closer inspection the styles are missing from the initial Server Side Render.

I suspect it is the require.extensions; just not sure how to solution so the SSR works.

It would be incredibly helpful if the Electrode artifact would just include a .scss example.

@didi0613
Copy link
Contributor

didi0613 commented Apr 11, 2018

Hello,
Here is a small example for electrode component with sass: https://github.com/didi0613/oss-electrode-component-sass-example
The example is a client side render component, please follow the README steps to check it out and let me know if you have any issues.

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

No branches or pull requests

9 participants