简体   繁体   English

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

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

In my react project if I use some non-existent className from css modules file,在我的反应项目中,如果我使用 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>

it quietly fails without letting me know that this class does not exist.它悄悄地失败了,却没有让我知道这个 class 不存在。 How I can check if this class name exist or not and throw an error.如何检查此 class 名称是否存在并引发错误。 Would be great to receive an error during build time, when saving file.保存文件时,在构建期间收到错误会很棒。

If you are open to typescript solution, I found one TS plugin for you.如果您对 typescript 解决方案持开放态度,我为您找到了一个 TS 插件。

typescript-plugin-css-modules打字稿插件CSS模块

It can populate the styles object with type information for available keys.它可以使用可用密钥的类型信息填充styles object。

You don't have to switch whole project to typescript, you can add // @ts-check directive at the top of this file to enable the TS engine design time check.您不必将整个项目切换到 typescript,您可以在此文件顶部添加// @ts-check指令以启用 TS 引擎设计时检查。

Unless you want to put forth a pull request to add something like a strict mode option to the webpack loader itself, i dont think theres much you can do since its just a base object.除非您想提出拉取请求以向 webpack 加载程序本身添加诸如严格模式选项之类的东西,否则我认为您无能为力,因为它只是一个基本的 object。 An easy alternative is to just do styles.styleName.toString() , this way if styleName is undefined, it will throw an error.一个简单的替代方法是只做styles.styleName.toString() ,这样如果styleName未定义,它将引发错误。

Actually it is possible in javascript code.实际上在 javascript 代码中是可能的。 But I think that className exist check is not good idea.但我认为 className 存在检查不是一个好主意。

document.styleSheets[].rules[].selectorText

original link How can you determine if a css class exists with Javascript?原始链接如何确定 css class 是否与 Javascript 一起存在?

add this function to the top:将此 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>
...

NOTE: This solution does not require you to change any of your code, just add the loader and it should work out of the box.注意:此解决方案不需要您更改任何代码,只需添加加载程序,它应该可以开箱即用。 Please note the caveat about production builds at the end, or check the source for full instructions at Github.请注意最后关于生产版本的警告,或查看源代码以获取 Github 的完整说明。

I have created a Webpack loader that works with CSS/LESS/Other CSS module loaders.我创建了一个与 CSS/LESS/其他 CSS 模块加载器一起使用的 Webpack 加载器。

The full source and readme can be found on GitHub .完整的源代码和自述文件可以在 GitHub 上找到

For those who just want to add the loader to their project, it can be used like this:对于那些只想将加载器添加到他们的项目的人,可以像这样使用它:

Add this webpack loader source file somewhere, eg /webpack/loaders/css-module-proxy.js在某处添加此 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);
    }
};

And then use it from your webpack config, example below is for LESS:然后从您的 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" },
    ],
},

Don't forget to build your release code with NODE_ENV=production or it may crash when a user visits your site...不要忘记使用NODE_ENV=production构建您的发布代码,否则它可能会在用户访问您的站点时崩溃...

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

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