繁体   English   中英

检测 CSS 模块/React 中不存在的类名的使用

[英]Detect use of non-existent classNames in CSS Modules/React

在我的反应项目中,如果我使用 css 模块文件中的一些不存在的类名,

 // mycss.modules.scss

.thing { color: red }

// index.jsx

import styles from mycss.modules.scss

<div className={styles.otherThing}>Some div</div>

// Browser would return:

<div>Some div</div>

它悄悄地失败了,却没有让我知道这个 class 不存在。 如何检查此 class 名称是否存在并引发错误。 保存文件时,在构建期间收到错误会很棒。

如果您对 typescript 解决方案持开放态度,我为您找到了一个 TS 插件。

打字稿插件CSS模块

它可以使用可用密钥的类型信息填充styles object。

您不必将整个项目切换到 typescript,您可以在此文件顶部添加// @ts-check指令以启用 TS 引擎设计时检查。

除非您想提出拉取请求以向 webpack 加载程序本身添加诸如严格模式选项之类的东西,否则我认为您无能为力,因为它只是一个基本的 object。 一个简单的替代方法是只做styles.styleName.toString() ,这样如果styleName未定义,它将引发错误。

实际上在 javascript 代码中是可能的。 但我认为 className 存在检查不是一个好主意。

document.styleSheets[].rules[].selectorText

原始链接如何确定 css class 是否与 Javascript 一起存在?

将此 function 添加到顶部:

// index.jsx
import styles from mycss.modules.scss

function strictStyles (clsName){
  if(styles[clsName]){
    return styles[clsName]
  }else{
    throw "CSS class doesn't exist";
  }
}

...
<div className={strictStyles(otherThing)}>Some div</div>
...

注意:此解决方案不需要您更改任何代码,只需添加加载程序,它应该可以开箱即用。 请注意最后关于生产版本的警告,或查看源代码以获取 Github 的完整说明。

我创建了一个与 CSS/LESS/其他 CSS 模块加载器一起使用的 Webpack 加载器。

完整的源代码和自述文件可以在 GitHub 上找到

对于那些只想将加载器添加到他们的项目的人,可以像这样使用它:

在某处添加此 webpack 加载程序源文件,例如/webpack/loaders/css-module-proxy.js

/**
 * A CSS/LESS/Style module loader that prepends a proxy in non-production builds.
 *
 * The proxy checks if the loaded style module actually contains the style we are trying to fetch.
 * If it doesn't exist (its accessor returns undefined), we crash on debug (non-production) builds!
 *
 * Inspired by https://github.com/royriojas/css-local-loader
 */
module.exports = function cssLocalLoader(source, map) {
    this.cacheable();
    if (process.env.NODE_ENV !== "production") {
        // noMatch:
        // Makes sure that any access prefixed with underscore are filtered out
        // otherwise it will crash at runtime when Webpack is probing the locals export.
        // toJsonMatch:
        // Makes sure that toJSON access on the locals object gets proxied to the correct
        // toJSON function.
        const requireWrapper = `
            // If the access matches this regexp, skip it
            const oldLocals = exports.locals;
            const noMatch = /^[_]+/;
            const toJsonMatch = /^toJSON$/;
            const proxy = new Proxy(oldLocals, {
              get: function(target, name) {
                if (noMatch.test(name)) {
                    return undefined;
                }
                if (toJsonMatch.test(name)) {
                    return oldLocals.toJSON;
                }
                const clz = target[name];
                if (clz === undefined) {
                    throw new Error("Error: LESS / CSS class named \\"" + name + "\\" does not exist");
                }
                return clz;
              }
            });
            exports.locals = proxy;
        `;
        const newSource = `${source}\n\n${requireWrapper}`;
        this.callback(null, newSource, map);
    } else {
        this.callback(null, source, map);
    }
};

然后从您的 webpack 配置中使用它,下面的示例用于 LESS:

{
    test: /\.module\.less$/,
    use: [
        { loader: path.resolve("webpack/loaders/css-module-proxy.js") },
        {
            loader: "css-loader",
            options: {
                modules: true,
                importLoaders: 1,
                localIdentName: "[name]__[local]__[hash:base64:5]",
            },
        },
        { loader: "less-loader" },
    ],
},

不要忘记使用NODE_ENV=production构建您的发布代码,否则它可能会在用户访问您的站点时崩溃...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM