[英]How to set className without {styles.red} in Next.js
I want to use only the pure name of the class without {styles.class-name} convention in Next.js, I google it and find I need to configure the next.config.js file.我只想在 Next.js 中使用没有 {styles.class-name} 约定的类的纯名称,我谷歌它并发现我需要配置 next.config.js 文件。 So, have someone good references for this?
那么,有人对此有很好的参考吗?
And it works fine in Next.js它在 Next.js 中运行良好
This is not working by default in Next.js这在 Next.js 中默认不起作用
Next.js has globals.css file and it's in styles folder so you can make: Next.js 有 globals.css 文件,它在样式文件夹中,因此您可以:
className="red"
and then in globals.css file:然后在 globals.css 文件中:
.red{
//...
}
But I recommend you to use .module.css files because it's cleaner and doesn't make a mess.但我建议你使用.module.css文件,因为它更干净而且不会弄乱。
I hadn't checked this earlier.我之前没有检查过这个。 You can directly use
babel-plugin-react-css-modules
.你可以直接使用
babel-plugin-react-css-modules
。
I had earlier wrote a Babel plugin for this.我之前为此编写了一个 Babel 插件。 It is not robust, can be improved, but does the job:
它不健壮,可以改进,但可以完成工作:
// babel-plugin-cx.js
const __path = require('path');
const plugin = ({ types: t }) => {
const cloneNode = t.cloneNode || t.cloneDeep;
return {
name: 'babel-plugin-cx',
visitor: {
Program: {
enter(path, state) {
state.stylesIdentifier = path.scope.generateUidIdentifier('styles');
},
exit(path, state) {
if (state.hasProp) {
const importDeclaration = t.importDeclaration(
[t.importDefaultSpecifier(state.stylesIdentifier)],
t.stringLiteral(
__path
.parse(state.file.opts.filename)
.name.toLowerCase()
.replace(/^([^]*)$/, state.opts.pathReplace),
),
);
path.node.body.unshift(importDeclaration);
}
},
},
JSXAttribute(path, state) {
if (path.node.name.name !== state.opts.propName) return;
if (
state.opts.ignoredElements.includes(
path.findParent((p) => p.isJSXOpeningElement()).node.name.name,
)
)
return;
path.node.name.name = 'className';
const value = path.get('value');
if (value.isLiteral()) {
value.replaceWith(
t.jsxExpressionContainer(
t.memberExpression(
cloneNode(state.stylesIdentifier),
cloneNode(value.node),
true,
false,
),
),
);
state.hasProp = true;
} else if (value.isJSXExpressionContainer()) {
const expression = value.get('expression');
expression.replaceWith(
t.memberExpression(
cloneNode(state.stylesIdentifier),
cloneNode(expression.node),
true,
false,
),
);
state.hasProp = true;
}
},
JSXSpreadAttribute(path, state) {
if (
state.opts.ignoredElements.includes(
path.findParent((p) => p.isJSXOpeningElement()).node.name.name,
)
)
return;
const argument = path.get('argument');
if (!argument.isObjectExpression()) return;
const properties = argument.get('properties');
for (const property of properties) {
if (property.node.key.name === state.opts.propName) {
property.node.key.name = 'className';
const value = property.get('value');
value.replaceWith(
t.memberExpression(
cloneNode(state.stylesIdentifier),
cloneNode(value.node),
true,
false,
),
);
state.hasProp = true;
}
}
},
},
};
};
module.exports = plugin;
// .babelrc
{
"presets": ["next/babel"],
"plugins": [
[
"./babel-plugin-cx",
{
"pathReplace": "./$1.module.css",
"propName": "cx",
"ignoredElements": ["circle", "ellipse", "radialGradient"]
}
]
]
}
If using Typescript, you need to add this (also add this file to includes
array in tsconfig.json
:如果使用 Typescript,则需要添加此文件(还将此文件添加到
tsconfig.json
includes
数组:
// custom.d.ts
import type * as React from 'react';
declare module 'react' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions, @typescript-eslint/no-unnecessary-qualifier
interface HTMLAttributes<T> extends React.DOMAttributes<T> {
cx?: string;
}
}
After this, you can simply write:在此之后,您可以简单地编写:
<div cx="red">Red text!</div>
There is no need to import the module file.无需导入模块文件。 It will be automatically imported if necessary from the specified
"pathReplace"
option.如有必要,它将从指定的
"pathReplace"
选项自动导入。 ( $1
indicates the file name using the cx
attribute). (
$1
使用cx
属性表示文件名)。
pathReplace
example: pathReplace
示例:
@styles/_$1.module.scss
: if file using cx
is Component.tsx
then the styles will be imported from module @styles/_component.module.scss
. @styles/_$1.module.scss
:如果使用cx
文件是Component.tsx
则样式将从模块@styles/_component.module.scss
。
You can configure the propName
using the provided option.您可以使用提供的选项配置
propName
。 You will also need to change next-env.d.ts
accordingly.您还需要相应地更改
next-env.d.ts
。 And, change the ignoredElements
option accordingly, as your attribute name may be same as some attribute defined in the JSX/HTML standard.并且,相应地更改
ignoredElements
选项,因为您的属性名称可能与 JSX/HTML 标准中定义的某些属性相同。
Caveats:注意事项:
The plugin currently completely ignores className
attribute if cx
is set on the element/component, ie, if you need to merge with some global class name then use className={`global ${styles.red}`}
.如果在元素/组件上设置了
cx
,插件当前完全忽略className
属性,即,如果您需要与某些全局类名合并,则使用className={`global ${styles.red}`}
。
More than one class in cx
is not supported.不支持
cx
多个类。 Can be implemented easily, but I was quite lazy.可以很容易地实现,但我很懒惰。
Spread attribute is only partially supported:仅部分支持 Spread 属性:
// supported: <div {...{cx: "red", other: "attribute"}}>Red text!</div> // not supported: const attrs = {cx: "red", other: "attribute"}; <div {...attrs}>Red text!</div>
You may like to configure this rule in ESLint react/jsx-props-no-spreading
.您可能希望在 ESLint
react/jsx-props-no-spreading
配置此规则。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.