3

TL;博士

  • 你如何告诉 SWC 编译在 React 组件中导入的 CSS 文件?
  • 你如何告诉 SWC 在测试和 React 组件中编译绝对导入?

这是一个最小的可重现示例。


语境

我们正在从 Babel 迁移到SWC。(我刚才问了一个问题。我正在改进那个问题的答案。)

我们从以下位置迁移命令:

"test": "NODE_ENV=test riteway -r @babel/register 'src/**/*.test.js' | tap-nirvana",

"test": "SWC_NODE_PROJECT=./jsconfig.json riteway -r @swc-node/register src/**/*.test.js | tap-nirvana",

jsconfig.json看起来像这样:

{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": "./src",
    "jsx": "react-jsx"
  }
}

如果我们编写尝试为自包含组件(没有绝对导入,没有 CSS)编译测试,它可以工作:

import { describe } from 'riteway';
import render from 'riteway/render-component';

function HomePageComponent({ user: { email } }) {
  return <p>{email}</p>;
}

describe('home page component', async assert => {
  const user = { email: 'foo' };
  const $ = render(<HomePageComponent user={user} />);

  assert({
    given: 'a user',
    should: 'render its email',
    actual: $('p').text(),
    expected: user.email,
  });
});

测试编译良好。

使用 Babel,我们有.babelrc这样的:

{
  "env": {
    "test": {
      "plugins": [
        [
          "module-resolver",
          {
            "root": [
              "."
            ],
            "alias": {
              "components": "./src/components",
              "config": "./src/config",
              "features": "./src/features",
              "hocs": "./src/hocs",
              "hooks": "./src/hooks",
              "pages": "./src/pages",
              "redux": "./src/redux",
              "styles": "./src/styles",
              "tests": "./src/tests",
              "utils": "./src/utils"
            }
          }
        ]
      ]
    }
  },
  "presets": [
    [
      "next/babel",
      {
        "ramda": {}
      }
    ]
  ],
  "plugins": [
    ["styled-components", { "ssr": true }]
  ]
}

样式由 styled-components 处理,而绝对导入则通过module-resolver插件定义。(我们从样式化组件切换到 CSS 模块,这就是我们从.module.cssCSS 文件导入的原因。无论如何......)

如果我们编写测试,我们希望如何使用它们的实际导入来编写它,如下所示:

import { describe } from 'riteway';
import render from 'riteway/render-component';
import { createPopulatedUserProfile } from 'user-profile/user-profile-factories';

import HomePageComponent from './home-page-component';

describe('home page component', async assert => {
  const user = createPopulatedUserProfile();
  const $ = render(<HomePageComponent user={user} />);

  assert({
    given: 'a user',
    should: 'render its email',
    actual: $('p').text(),
    expected: user.email,
  });
});

它失败了:

$ SWC_NODE_PROJECT=./jsconfig.json riteway -r @swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
/Users/janhesters/dev/my-project/src/features/home/home.module.css:1
(function (exports, require, module, __filename, __dirname) { .container {
                                                              ^

SyntaxError: Unexpected token '.'

当我们在 CSS 导入中离开时home-page-component.js,或者使用:

$ SWC_NODE_PROJECT=./jsconfig.json riteway -r @swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module 'user-profile/user-profile-factories'
Require stack:
- /Users/janhesters/dev/my-project/src/features/home/home-page-component.test.js
- /Users/janhesters/dev/my-project/node_modules/riteway/bin/riteway

分别,当我们摆脱 CSS 导入时。

我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)以及我们如何帮助它理解绝对导入?

我们已经设置baseUrljsconfig.json...

4

3 回答 3

3

关于绝对路径

您已经添加baseUrljsconfig.json文件但没有添加路径,您应该像我的一样修改您的配置文件:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@screens": ["./screens"],
      "@shared": ["./shared"],
      "@shared/*": ["./shared/*"]
    },

路径是aliasof module-resolver,我猜你root不应该是".",它应该和你的jsconfig.json文件完全一样,我的意思是baseUrl值。

  "plugins": [
    [
      "module-resolver",
      {
        "root": ["./src"],
        "extensions": [".ts", ".tsx", ".js", ".jsx", ".json"],
        "alias": {
          "@screens": "./src/screens",
          "@shared": "./src/shared"
        }
      }
    ]
  ],

如果你有 Webpack,你应该alias在你resolve的 Webpack 配置对象的键中有配置,就像我的一样:

const resolve = {
  extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
  alias: {
    '@screens': path.join(__dirname, 'src/screens/'),
    '@shared': path.join(__dirname, 'src/shared/'),
  },
  modules: ['src', 'node_modules'],
  descriptionFiles: ['package.json'],
};

关于 CSS

实际上,您使用 CSS 文件作为 CSS-Modules 不像推荐的 NexJS doc,在文档中开发人员应该像导入 CSS 一样import './styles.css',然后像string在 JSX 中一样使用它<div className="main"

您正在像模块(CSS-Module)一样导入它:

// you did it

import styles from './styles.css';

<div className={styles.main}

如您所知,它是这个文档的内置支持,NextJS 支持它,但 SWC 无法理解它。我花了几个小时来寻找一种方法,但似乎 SWC 还不支持 CSS-Module。您应该为 SWC 创建自己的插件以支持 CSS-Module。

于 2022-02-03T00:43:15.450 回答
0
  1. 我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)?- SWC 本身不理解 css,Babel 也不理解。正如你所指出的,当你使用 Babel 时,插件styled-components会处理这个问题。您需要对 SWC 执行相同的操作。我找不到执行此操作的现有 SWC 插件,但您可以推出自己的. 显然这是一种痛苦,但这就是使用新工具的成本。
  2. 我们如何帮助 SWC 了解绝对进口?-.swrc选项baseUrlpaths应该做你想做的事,但这似乎也有一些问题

你可能有更好的运气直接在@swc-nodeGitHub 存储库中创建问题,但鉴于那里的评论,感觉你可能会成为 SOL 一段时间。使用Next开箱即用支持的库之一可能会更快/更容易地重写您的测试。

于 2022-01-31T22:53:10.643 回答
0

我能够在不编写任何插件的情况下解决所有问题。我从问题中将解决方案推送到我的示例存储库

首先,使用官方SWC 项目的 register。这意味着,您必须像这样编译测试:

"test": "riteway -r @swc/register 'src/**/*.test.js' | tap-nirvana",

您可以通过运行安装它:

yarn add --dev @swc/core @swc/register

我们需要这个版本的寄存器,因为它考虑了一个.swcrc文件,而另一个没有。

其次,您需要同时"path"修复"baseUrl"绝对导入,因为出于某种原因,SWC 不会仅通过"baseUrl"提供的路径推断所有路径。你需要调整你的.swcrc来处理 React。

{
  "jsc": {
    "baseUrl": "./src",
    "paths": {
      "*.css": ["utils/identity-object-proxy.js"],
      "utils/*": ["utils/*"]
    },
    "parser": {
      "jsx": true,
      "syntax": "ecmascript"
    },
    "transform": {
      "react": {
        "runtime": "automatic"
      }
    }
  },
  "module": {
    "type": "commonjs"
  }
}

第三,要解决此问题,.css您需要将所有导入.css文件重新映射到身份对象代理,您可以在.swcrc上面的示例中看到。身份对象代理是一个对象,当您引用任何属性时,它会返回您尝试引用的字符串化键。您可以像这样自己创建一个:

const identityObjectProxy = new Proxy(
  {},
  {
    get: function getter(target, key) {
      if (key === '__esModule') {
        return false;
      }
      return key;
    },
  },
);

export default identityObjectProxy;

要使.css重新映射生效,您需要将所有导入.css文件都设为绝对导入。(import styles from './styles.module.css不会工作!)

于 2022-02-21T19:55:41.333 回答