简体   繁体   English

SWC with JavaScript:如何处理CSS导入以及如何绝对导入?

[英]SWC with JavaScript: How to handle CSS imports and how to absolute imports?

TL;DR长话短说

  • How can you tell SWC to compile CSS files imported in React components?你怎么能告诉SWC去编译React组件中导入的CSS个文件呢?
  • How can you tell SWC to compile absolute imports in tests and in React components?你如何告诉 SWC 在测试和 React 组件中编译绝对导入?

Here is a minimal reproducible example.这是一个最小的可重现示例。


Context语境

We're migrating from Babel to SWC .我们正在从 Babel 迁移到SWC (I asked a question a little while ago. I'm improving on that question's answer.) (我刚才问了一个问题。我正在改进那个问题的答案。)

We're migrated the command from:我们从以下位置迁移了命令:

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

to

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

where the jsconfig.json looks like this:其中jsconfig.json看起来像这样:

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

If we write try to compile a test for a self-contained component (no absolute imports, no CSS) it works:如果我们尝试为独立组件(没有绝对导入,没有 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,
  });
});

The test compiles fine.测试编译正常。

With Babel we had a .babelrc like this:使用 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 }]
  ]
}

Where the styles where taken care of by styled-components and the absolute imports where defined via the module-resolver plugin.其中 styles 由 styled-components 处理,而绝对导入是通过module-resolver插件定义的。 (We switched away from styled-components to CSS modules, which is why we import from .module.css CSS files. Anyways...) (我们从 styled-components 切换到 CSS 模块,这就是我们从.module.css CSS 文件导入的原因。无论如何......)

If we write the test how we wanted to write it with their actual imports like this:如果我们编写测试,我们希望如何使用他们的实际导入来编写它,如下所示:

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,
  });
});

It fails with:它失败了:

$ 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 '.'

when we leave in the CSS import in home-page-component.js , or with:当我们离开home-page-component.js中的 CSS 导入时,或者:

$ 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

respectively, when we get rid of the CSS import.分别,当我们摆脱 CSS 进口。

How can we help SWC understand CSS (or mock CSS modules) and how can we help it understand absolute imports?我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)以及我们如何帮助它理解绝对导入?

We already set the baseUrl in jsconfig.json ...我们已经在jsconfig.json baseUrl

  1. How can we help SWC understand CSS (or mock CSS modules)?我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)? - SWC doesn't understand css natively, and neither did Babel. - SWC 本身不理解 css,Babel 也不理解。 As you noted, when you were using Babel, the plugin styled-components took care of this.正如你所提到的,当你使用 Babel 时,插件styled-components会处理这个问题。 You'll need to do the same with SWC.您需要对 SWC 执行相同的操作。 I can't find an existing SWC plugin that does this, but you can roll your own .我找不到执行此操作的现有 SWC 插件,但您可以推出自己的. Obviously this is a pain, but such is the cost of using new tooling.显然这是一种痛苦,但这就是使用新工具的成本。
  2. How can we help SWC understand absolute imports?我们如何帮助 SWC 了解绝对进口? - The .swrc options for baseUrl and paths should do what you want, but that, too, seems to have some issues . - baseUrlpaths.swrc选项应该做你想做的事,但这似乎也有一些问题

You may have better luck creating issues directly in the @swc-node GitHub repo, but given the comments there it feels like you might be SOL for a while.直接在@swc-node GitHub 存储库中创建问题可能会更好,但鉴于那里的评论,感觉你可能会成为 SOL 一段时间。 Might be faster/easier to rewrite your tests using one of the libraries that Next supports out of the box.使用Next 开箱即用支持的库之一可能会更快/更容易地重写您的测试。

About absolute path关于绝对路径

You already add baseUrl in the jsconfig.json file but didn't add the paths, you should modify your config file like mine:您已经在jsconfig.json文件中添加了baseUrl但没有添加路径,您应该像我一样修改您的配置文件:

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

The paths are the alias of module-resolver , and I guess your root shouldn't be "."路径是module-resolveralias ,我猜你的root不应该是"." , it should be exactly like your jsconfig.json file, I mean the baseUrl value. ,它应该与您的jsconfig.json文件完全相同,我的意思是baseUrl值。

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

If you have Webpack, you should have alias config in your resolve key off Webpack config object, like mine:如果你有 Webpack,你应该在你的resolve键中有alias配置关闭 Webpack 配置 object,就像我的:

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'],
};

About CSS关于CSS

Actually, you are using CSS file as CSS-Modules not like recommended NexJS doc , in docs developer should import CSS like import './styles.css' and then use it as string in JSX like <div className="main"实际上,您使用 CSS 文件作为 CSS-Modules 不像推荐的 NexJS doc ,在文档中开发人员应该像import './styles.css'一样导入 CSS ,然后在 JSX 中将其用作string ,如<div className="main"

But

You are importing it like a module (CSS-Module):您正在像模块(CSS-Module)一样导入它:

// you did it

import styles from './styles.css';

<div className={styles.main}

As you know it is built-in support by this doc , it is supported by NextJS, but SWC cannot understand it.如您所知,它是这个文档的内置支持,NextJS 支持它,但 SWC 无法理解它。 I put in hours to find a way for it, but it seems SWC doesn't support CSS-Module yet.我花了几个小时来寻找一种方法,但似乎 SWC 还不支持 CSS-Module。 you should create your own plugin for SWC to support CSS-Module.您应该为 SWC 创建自己的插件以支持 CSS-Module。

I was able to solve all issues without writing any plugins.我能够在不编写任何插件的情况下解决所有问题。 I pushed the solution to my example repo from the question.我从问题中将解决方案推到了我的示例回购中。

Firstly, use the official SWC project's register .首先,使用官方的 SWC 项目的 register This means, you have to compile your tests like this:这意味着,您必须像这样编译测试:

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

You can install it by running:您可以通过运行以下命令来安装它:

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

We need this version of register, because it takes into account an .swcrc file, which the other one did not.我们需要这个版本的寄存器,因为它考虑了一个.swcrc文件,而另一个没有。

Secondly, you need both "path" and "baseUrl" to fix the absolute imports because for some reason SWC doesn't infer all paths with only a "baseUrl" provided.其次,您需要"path""baseUrl"来修复绝对导入,因为出于某种原因,SWC 不会仅提供"baseUrl"来推断所有路径。 And you need to adapt your .swcrc to handle React.你需要调整你的.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"
  }
}

Thirdly, to solve .css you need to remap all imports to .css files to an identity object proxy, which you can see in the .swcrc example above.第三,要解决.css ,您需要将所有对.css文件的导入重新映射到身份 object 代理,您可以在上面的.swcrc示例中看到。 An identity object proxy is an object that, when you reference any property, returns the stringified key that you're trying to reference.身份 object 代理是一个 object,当您引用任何属性时,它会返回您尝试引用的字符串化键。 You can create one yourself like this:你可以像这样自己创建一个:

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

export default identityObjectProxy;

For the .css remap to go into effect you need to make all your imports to .css files absolute imports.要使.css重新映射到 go 生效,您需要将所有导入到.css文件的文件绝对导入。 ( import styles from './styles.module.css won't work!) import styles from './styles.module.css不会工作!)

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

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