nodejh
7/6/2018 - 3:12 PM

cra antd css/less module

cra antd css/less module

// https://github.com/timarney/react-app-rewired/issues/116

const path = require("path");

const { compose, getLoader, injectBabelPlugin } = require("react-app-rewired");

const rewireLessModules = (prefix = "", lessOptions = {}) => {
  const cloneDeep = require("lodash/clonedeep");

  const ruleChildren = loader =>
    loader.use ||
    loader.oneOf ||
    (Array.isArray(loader.loader) && loader.loader) ||
    [];

  const findIndexAndRules = (rulesSource, ruleMatcher) => {
    let result = undefined;
    const rules = Array.isArray(rulesSource)
      ? rulesSource
      : ruleChildren(rulesSource);
    rules.some(
      (rule, index) =>
        (result = ruleMatcher(rule)
          ? { index, rules }
          : findIndexAndRules(ruleChildren(rule), ruleMatcher)),
    );
    return result;
  };

  const findRule = (rulesSource, ruleMatcher) => {
    const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
    return rules[index];
  };

  const cssRuleMatcher = rule =>
    rule.test && String(rule.test) === String(/\.css$/);

  const createLoaderMatcher = loader => rule =>
    rule.loader && rule.loader.indexOf(`/${loader}/`) !== -1;
  const cssLoaderMatcher = createLoaderMatcher("css-loader");
  const postcssLoaderMatcher = createLoaderMatcher("postcss-loader");
  const fileLoaderMatcher = createLoaderMatcher("file-loader");

  const addAfterRule = (rulesSource, ruleMatcher, value) => {
    const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
    rules.splice(index + 1, 0, value);
  };

  const addBeforeRule = (rulesSource, ruleMatcher, value) => {
    const { index, rules } = findIndexAndRules(rulesSource, ruleMatcher);
    rules.splice(index, 0, value);
  };

   return function(config, env) {
    const cssRule = findRule(config.module.rules, cssRuleMatcher);
    cssRule.exclude = path.resolve(__dirname, "src");
    cssRule.include = path.resolve(__dirname, "node_modules");

    const lessRule = cloneDeep(cssRule);
    lessRule.test = /\.less$/;
    const cssModulesRule = cloneDeep(cssRule);

    cssModulesRule.include = path.resolve(__dirname, "src");
    cssModulesRule.exclude = path.resolve(__dirname, "node_modules");

    const cssModulesRuleCssLoader = findRule(cssModulesRule, cssLoaderMatcher);
    cssModulesRuleCssLoader.options = Object.assign(
      {
        modules: true,
        localIdentName: `${env === "production"
          ? prefix
          : "[local]"}-[hash:base64:8]`,
      },
      cssModulesRuleCssLoader.options,
    );
    addBeforeRule(config.module.rules, fileLoaderMatcher, cssModulesRule);

    addAfterRule(lessRule, postcssLoaderMatcher, {
      loader: require.resolve("less-loader"),
      options: lessOptions,
    });
    addBeforeRule(config.module.rules, fileLoaderMatcher, lessRule);

    const lessModulesRule = cloneDeep(cssModulesRule);
    lessModulesRule.test = lessRule.test;

    addAfterRule(
      lessModulesRule,
      postcssLoaderMatcher,
      require.resolve("less-loader"),
    );
    addBeforeRule(config.module.rules, fileLoaderMatcher, lessModulesRule);

    return config;
  };
};

module.exports = function override(config, env) {
  config = injectBabelPlugin(
    ["import", { libraryName: "antd", style: true, libraryDirectory: "es" }],
    config,
  );

  const rewires = compose(
    // rewireHTML,
    rewireLessModules("comment", {
      javascriptEnabled: true,
      modifyVars: {
        "@font-size-base": "14px",
      },
    }),
  );

  return rewires(config, env);
};