webpack 转换 less,开启 CSS Modules 后背景图片失效

开发背景

使用 create-react-app 创建 React 项目后,通过 react-app-rewired 开启了 less 转换的功能。

但通过抄袭 react-app-rewire-css-modules 模块开启 CSS Modules 发现在 *.module.less 里面的背景图片失效,需要修改图片路径为 ../yourdir/yourImage 的方式才能有效解决(进入上一层级目录,在进入当前文件夹目录)。

issues 上面也有一个类似的问题,CSS background img path error

解决方案

需要在转换 less 的后面加一个 loader,名字是 resolve-url-loader

如果是 sass 可以参考上面的 issues 修复问题。

react-app-rewired 方案,代码如下:

/**
 * less
 * 抄袭:https://github.com/codebandits/react-app-rewire-css-modules
 */
const path = require('path');
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(`${path.sep}${loader}${path.sep}`) !== -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);
};

function createRewireLess({
    localIdentName = `[local]___[hash:base64:5]`,
    lessLoaderOptions = {}
}) {
    return function(config, env) {
        const cssRule = findRule(config.module.rules, cssRuleMatcher);
        const sassRule = cloneDeep(cssRule);
        const cssModulesRule = cloneDeep(cssRule);

        cssRule.exclude = /\.module\.css$/;

        const cssModulesRuleCssLoader = findRule(
            cssModulesRule,
            cssLoaderMatcher
        );
        cssModulesRuleCssLoader.options = Object.assign(
            { modules: true, localIdentName },
            cssModulesRuleCssLoader.options
        );
        addBeforeRule(config.module.rules, fileLoaderMatcher, cssModulesRule);

        sassRule.test = /\.less$/;
        sassRule.exclude = /\.module\.less$/;
        addAfterRule(sassRule, postcssLoaderMatcher, {
            loader: require.resolve('less-loader'),
            options: lessLoaderOptions
        });

        addBeforeRule(config.module.rules, fileLoaderMatcher, sassRule);

        const sassModulesRule = cloneDeep(cssModulesRule);
        sassModulesRule.test = /\.module\.less$/;
        // sassModulesRule.exclude = path.resolve(__dirname, 'node_modules');
        // fix image url
        addAfterRule(sassModulesRule, postcssLoaderMatcher, {
            loader: require.resolve('resolve-url-loader')
        });
        addAfterRule(sassModulesRule, postcssLoaderMatcher, {
            loader: require.resolve('less-loader'),
            options: lessLoaderOptions
        });
        addBeforeRule(config.module.rules, fileLoaderMatcher, sassModulesRule);

        return config;
    };
}

const rewireLess = createRewireLess({});

rewireLess.withLoaderOptions = createRewireLess;

module.exports = rewireLess;

如果是 webpack 的配置,如下:

let module = {
    importLoaders: 3,
    modules: true,
    localIdentName: '[name]_[local]_[hash:base64:5]'
};
let loaders = [
    {
        loader: 'css-loader',
        options: module
    },
    {
        loader: 'postcss-loader',
        options: {
            plugins: [require('autoprefixer')('last 100 versions')]
        }
    },
    {
        loader: 'resolve-url-loader'
    },
    {
        loader: 'less-loader',
        options: {
            javascriptEnabled: true,
            modifyVars: { '@primary-color': '#1DA57A' }
        }
    }
];
原文阅读:webpack 转换 less,开启 CSS Modules 后背景图片失效

相关推荐