带有 JavaScript 的 SWC:如何处理 CSS 导入以及如何进行绝对导入?
SWC with JavaScript: How to handle CSS imports and how to absolute imports?
TL;DR
- 如何告诉 SWC 编译在 React 组件中导入的 CSS 个文件?
- 如何告诉 SWC 在测试和 React 组件中编译绝对导入?
Here is a minimal reproducible example.
上下文
我们刚刚从 Babel 迁移到 SWC. (I asked a 。我正在改进那个问题的答案。)
我们从以下位置迁移了命令:
"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
插件定义。 (我们从 styled-components 切换到 CSS 模块,这就是我们从 .module.css
CSS 文件导入的原因。无论如何...)
如果我们像这样用他们的实际导入来编写我们想要编写的测试:
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 模块)以及我们如何帮助它理解绝对导入?
我们已经在 jsconfig.json
中设置了 baseUrl
...
- 我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)? - SWC 本身不理解 css,巴别塔也没有。正如您所指出的,当您使用 Babel 时,插件
styled-components
会处理这个问题。您需要对 SWC 执行相同的操作。我找不到执行此操作的现有 SWC 插件,但您可以 roll your own。显然这很痛苦,但这就是使用新工具的成本。
- 我们如何帮助 SWC 理解绝对导入? -
baseUrl
和 paths
的 .swrc
选项应该做你想做的,但这也是 seems to have some issues.
直接在 @swc-node
GitHub 回购中创建问题可能会更好,但考虑到那里的评论,感觉你可能会 SOL 一段时间。可能 faster/easier 使用 Next supports 开箱即用的库之一重写您的测试。
关于绝对路径
你已经在 jsconfig.json
文件中添加了 baseUrl
但没有添加路径,你应该像我一样修改你的配置文件:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@screens": ["./screens"],
"@shared": ["./shared"],
"@shared/*": ["./shared/*"]
},
路径是module-resolver
的alias
,我猜你的root
不应该是"."
,应该和你的[=15=一样] 文件,我的意思是 baseUrl
值。
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".ts", ".tsx", ".js", ".jsx", ".json"],
"alias": {
"@screens": "./src/screens",
"@shared": "./src/shared"
}
}
]
],
如果你有 Webpack,你应该在你的 resolve
关键 Webpack 配置对象中有 alias
配置,就像我的一样:
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 而不是 recommended NexJS doc,在文档中开发人员应该像 import './styles.css'
一样导入 CSS 然后使用它作为 JSX 中的 string
就像 <div className="main"
但是
您正在像模块一样导入它 (CSS-Module):
// you did it
import styles from './styles.css';
<div className={styles.main}
如你所知是built-in由this doc支持,NextJS支持,但是SWC看不懂。我花了几个小时来寻找解决方法,但 SWC 似乎还不支持 CSS-Module。您应该为 SWC 创建自己的插件以支持 CSS-Module.
我能够在不编写任何插件的情况下解决所有问题。我把问题的解决方案推到了my example repo。
首先,使用官方SWC project's 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
示例中看到。身份对象代理是一个对象,当您引用任何 属性、returns 您尝试引用的字符串化键时。您可以像这样自己创建一个:
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
不行!)
TL;DR
- 如何告诉 SWC 编译在 React 组件中导入的 CSS 个文件?
- 如何告诉 SWC 在测试和 React 组件中编译绝对导入?
Here is a minimal reproducible example.
上下文
我们刚刚从 Babel 迁移到 SWC. (I asked a
我们从以下位置迁移了命令:
"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
插件定义。 (我们从 styled-components 切换到 CSS 模块,这就是我们从 .module.css
CSS 文件导入的原因。无论如何...)
如果我们像这样用他们的实际导入来编写我们想要编写的测试:
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 模块)以及我们如何帮助它理解绝对导入?
我们已经在 jsconfig.json
中设置了 baseUrl
...
- 我们如何帮助 SWC 理解 CSS(或模拟 CSS 模块)? - SWC 本身不理解 css,巴别塔也没有。正如您所指出的,当您使用 Babel 时,插件
styled-components
会处理这个问题。您需要对 SWC 执行相同的操作。我找不到执行此操作的现有 SWC 插件,但您可以 roll your own。显然这很痛苦,但这就是使用新工具的成本。 - 我们如何帮助 SWC 理解绝对导入? -
baseUrl
和paths
的.swrc
选项应该做你想做的,但这也是 seems to have some issues.
直接在 @swc-node
GitHub 回购中创建问题可能会更好,但考虑到那里的评论,感觉你可能会 SOL 一段时间。可能 faster/easier 使用 Next supports 开箱即用的库之一重写您的测试。
关于绝对路径
你已经在 jsconfig.json
文件中添加了 baseUrl
但没有添加路径,你应该像我一样修改你的配置文件:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@screens": ["./screens"],
"@shared": ["./shared"],
"@shared/*": ["./shared/*"]
},
路径是module-resolver
的alias
,我猜你的root
不应该是"."
,应该和你的[=15=一样] 文件,我的意思是 baseUrl
值。
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".ts", ".tsx", ".js", ".jsx", ".json"],
"alias": {
"@screens": "./src/screens",
"@shared": "./src/shared"
}
}
]
],
如果你有 Webpack,你应该在你的 resolve
关键 Webpack 配置对象中有 alias
配置,就像我的一样:
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 而不是 recommended NexJS doc,在文档中开发人员应该像 import './styles.css'
一样导入 CSS 然后使用它作为 JSX 中的 string
就像 <div className="main"
但是
您正在像模块一样导入它 (CSS-Module):
// you did it
import styles from './styles.css';
<div className={styles.main}
如你所知是built-in由this doc支持,NextJS支持,但是SWC看不懂。我花了几个小时来寻找解决方法,但 SWC 似乎还不支持 CSS-Module。您应该为 SWC 创建自己的插件以支持 CSS-Module.
我能够在不编写任何插件的情况下解决所有问题。我把问题的解决方案推到了my example repo。
首先,使用官方SWC project's 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
示例中看到。身份对象代理是一个对象,当您引用任何 属性、returns 您尝试引用的字符串化键时。您可以像这样自己创建一个:
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
不行!)