如何在 Nextjs 中散列 CSS 类名?

use*_*899 3 reactjs webpack css-modules css-loader next.js

如何在 Nextjs 中编辑Webpack 配置中的localIdentName字段,css-loader以便我可以散列/隐藏/混淆 css 类名?

下面的例子来自纽约时报。注意类名:

在此处输入图片说明

brc*_*-dd 26

此线程上的所有答案都不适用于较新的 Next.js 版本(v11.1.3-canary.2及更高版本),因为在PR#28529css-loader中,Next.js 团队已切换到具有 no 的自定义版本defaultGetLocalIdent,也不检查是否getLocalIndent是null或undefined。

任何最终getLocalIdent从加载器配置中删除的解决方案都将导致TypeError: getLocalIdent is not a function. 换句话说,现在必须提供一个函数 as getLocalIdent。这是一个例子:

const path = require('path');
const loaderUtils = require('loader-utils');

// based on https://github.com/vercel/next.js/blob/992c46e63bef20d7ab7e40131667ed3debaf67de/packages/next/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.ts
const hashOnlyIdent = (context, _, exportName) =>
  loaderUtils
    .getHashDigest(
      Buffer.from(
        `filePath:${path
          .relative(context.rootContext, context.resourcePath)
          .replace(/\\+/g, '/')}#className:${exportName}`,
      ),
      'md4',
      'base64',
      6,
    )
    .replace(/[^a-zA-Z0-9-_]/g, '_')
    .replace(/^(-?\d|--)/, '_$1');

module.exports = {
  webpack(config, { dev }) {
    const rules = config.module.rules
      .find((rule) => typeof rule.oneOf === 'object')
      .oneOf.filter((rule) => Array.isArray(rule.use));

    if (!dev)
      rules.forEach((rule) => {
        rule.use.forEach((moduleLoader) => {
          if (
            moduleLoader.loader?.includes('css-loader') &&
            !moduleLoader.loader?.includes('postcss-loader')
          )
            moduleLoader.options.modules.getLocalIdent = hashOnlyIdent;

            // earlier below statements were sufficient:
            // delete moduleLoader.options.modules.getLocalIdent;
            // moduleLoader.options.modules.localIdentName = '[hash:base64:6]';
        });
      });

    return config;
  },
};
Run Code Online (Sandbox Code Playgroud)

这也适用于 Next v12 和 v13(不带 TurboPack)。

演示:

开发的同时——

关于生产-

带有实验应用程序目录的演示:

  • 这在 nextjs 12.2.0 上对我有用,但我需要用最终哈希中的 _ 替换 + 和 / 。如果有人想尝试,这是我的完整文件:https://gist.github.com/herlon214/7da6a39b885014a5d5f51716f6530ce4 (4认同)

use*_*899 5

不幸的是,没有内置支持Nextjs将自定义配置传递给Webpack加载程序。但是我们可以通过使用next.config.js.

首先,next.config.js在项目目录的根目录中创建。

对于 Nextjs 11

module.exports = {
  webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
    config.module.rules[3].oneOf.forEach((moduleLoader, i) => {
      Array.isArray(moduleLoader.use) &&
        moduleLoader.use.forEach((l) => {
          if (
            l.loader.includes("\\css-loader") &&
            !l.loader.includes("postcss-loader")
          ) {
            const { getLocalIdent, ...others } = l.options.modules;

            l.options = {
              ...l.options,
              modules: {
                ...others,
                localIdentName: "[hash:base64:6]",
              },
            };
          }
        });
    });
    return config;
  },
};
Run Code Online (Sandbox Code Playgroud)

对于 Next.js 10.2 或更新版本:

module.exports = {
  webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
    config.module.rules[3].oneOf.forEach((moduleLoader, i) => {
      Array.isArray(moduleLoader.use) &&
        moduleLoader.use.forEach((l) => {
          if (
            l.loader.includes("\\css-loader") &&
            !l.loader.includes("postcss-loader")
          ) {
            const { getLocalIdent, ...others } = l.options.modules;

            l.options = {
              ...l.options,
              modules: {
                ...others,
                localIdentName: "[hash:base64:6]",
              },
            };
          }
        });
    });
    return config;
  },
};
Run Code Online (Sandbox Code Playgroud)

否则使用这个:

module.exports = {
  webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
    config.module.rules[1].oneOf.forEach((moduleLoader, i) => {
      Array.isArray(moduleLoader.use) &&
        moduleLoader.use.forEach((l) => {
          if (
            l.loader.includes('\\css-loader') &&
            !l.loader.includes('postcss-loader')
          ) {
            const { getLocalIdent, ...others } = l.options.modules;

            l.options = {
              ...l.options,
              modules: {
                ...others,
                localIdentName: '[hash:base64:6]',
              },
            };
          }
        });
    });
    return config;
  },
};
Run Code Online (Sandbox Code Playgroud)

如果只想在 production 中散列类名,则可以使用process.env.NODE_ENVwithif语句。像这样:

module.exports = {
  webpack(config, { buildId, dev, isServer, defaultLoaders, webpack }) {
    if (process.env.NODE_ENV === "production") {
      ...
      ...

      return config;
    } else {
      return config;
    }
  },
};
Run Code Online (Sandbox Code Playgroud)