You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js SSR场景下ESM项目中如何导入CSS Modules?

解决Node.js ESM环境下导入CSS模块的报错问题

方案1:使用@node-loader/css-modules(推荐,适配ESM)

这是专门为Node.js ESM设计的CSS模块加载器,能直接处理import style from './xxx.module.css'语法,还能配置和Webpack一致的类名生成规则。

  • 安装依赖:
    npm install @node-loader/css-modules --save-dev
    
  • 配置类名规则(可选,确保和Webpack一致):
    在项目根目录创建css-modules.config.json,写入和你Webpack配置中modules.localIdentName一致的规则,比如:
    {
      "generateScopedName": "[name]__[local]--[hash:base64:5]"
    }
    
  • 启动Node.js服务时指定加载器:
    修改package.json的启动脚本,或者直接在命令行添加参数:
    node --experimental-loader @node-loader/css-modules ./server-entry.js
    
    示例package.json脚本:
    {
      "scripts": {
        "start": "node --experimental-loader @node-loader/css-modules server.js"
      }
    }
    

方案2:自定义ESM加载器

如果需要更灵活的控制,可以自己编写Node.js ESM加载器,用PostCSS解析CSS模块。

  • 安装依赖:
    npm install postcss postcss-modules --save-dev
    
  • 创建加载器文件css-module-loader.mjs:
    import { readFile } from 'fs/promises';
    import postcss from 'postcss';
    import postcssModules from 'postcss-modules';
    
    // 配置类名生成规则,和Webpack保持一致
    const generateScopedName = '[name]__[local]--[hash:base64:5]';
    
    export async function load(url) {
      if (!url.endsWith('.module.css')) return null;
    
      const cssContent = await readFile(new URL(url), 'utf8');
      let classMap = {};
    
      await postcss([
        postcssModules({
          getJSON: (_, map) => { classMap = map; }
        })
      ]).process(cssContent, { from: url });
    
      // 将类名映射转为ESM模块代码
      const moduleCode = `export default ${JSON.stringify(classMap)};`;
      return { source: moduleCode };
    }
    
    // 其他必要的加载器钩子,直接返回默认值
    export function resolve(specifier, context, defaultResolve) {
      return defaultResolve(specifier, context);
    }
    
    export function transform(source, context, defaultTransform) {
      return defaultTransform(source, context);
    }
    
  • 启动服务时指定自定义加载器:
    node --experimental-loader ./css-module-loader.mjs ./server-entry.js
    

方案3:预生成CSS模块的JS映射文件(无实验性依赖)

如果不想依赖Node.js的实验性加载器,可以在构建阶段提前把CSS模块编译成ESM格式的JS文件,直接导出类名映射。

  • 编写编译脚本build-css-modules.mjs:
    import { readdir, readFile, writeFile } from 'fs/promises';
    import { join, extname, basename } from 'path';
    import postcss from 'postcss';
    import postcssModules from 'postcss-modules';
    
    const generateScopedName = '[name]__[local]--[hash:base64:5]';
    
    async function processCssModule(filePath) {
      const cssContent = await readFile(filePath, 'utf8');
      let classMap = {};
    
      await postcss([
        postcssModules({
          getJSON: (_, map) => { classMap = map; }
        })
      ]).process(cssContent, { from: filePath });
    
      // 生成对应的.mjs文件
      const outputPath = `${filePath}.mjs`;
      await writeFile(outputPath, `export default ${JSON.stringify(classMap)};`, 'utf8');
      console.log(`Generated ${outputPath}`);
    }
    
    async function scanDir(dir) {
      const files = await readdir(dir, { withFileTypes: true });
      for (const file of files) {
        const fullPath = join(dir, file.name);
        if (file.isDirectory()) {
          await scanDir(fullPath);
        } else if (extname(file.name) === '.css' && file.name.includes('.module.')) {
          await processCssModule(fullPath);
        }
      }
    }
    
    // 扫描src目录下的所有CSS模块文件
    scanDir('./src');
    
  • 运行脚本生成JS映射文件:
    node ./build-css-modules.mjs
    
  • 修改代码中的导入路径:
    将import style from './Body.module.css'改为import style from './Body.module.css.mjs',或者在TS/JS配置中添加路径别名,自动映射。

额外注意事项

  • TypeScript类型支持:如果用TSX,需要在项目中添加CSS模块的类型声明文件css-modules.d.ts:
    declare module '*.module.css' {
      const classes: { [key: string]: string };
      export default classes;
    }
    
  • Webpack配置对齐:确保所有方案中的generateScopedName和你Webpack配置里的modules.localIdentName完全一致,这样前后端的类名才能匹配。

内容的提问来源于stack exchange,提问作者Flion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 19:41:22