在CodeSandbox上创建React + TailwindCSS + twin.macro环境
The goal
我希望在想要轻松尝试一些实现的时候,不必每次都在本地环境中创建React应用程序,因此我创建了一个云环境上的实验场所。由于在想要轻松尝试时将CSS分开编写也很麻烦,所以我决定使用tailwindcss。因为我担心只使用tailwindcss可能无法满足复杂的布局需求,所以我还引入了twin.macro,使得可以在emotion中编写内联CSS。
CodeSandbox是什么
这是一个在云端上能够创建各种环境的便捷的网站。只需选择模板,即可帮助您创建应用程序,无论是React应用程序,还是Next.js、Vue.js、Node.js等都可选择。就React而言,您可以通过选择模板来实现想要使用vite而不是create-react-app作为构建系统,或者想要引入typescript的需求。
环境
在CodeSandbox上构建以下环境。
React(使用Vite和Typescript)
TailwindCSS
twin.macro
步骤
在CodeSandbox上使用React模板创建应用程序。



用React模板创建应用程序已经完成。
安装TailwindCSS
参考TailwindCSS公式文档并安装TailwindCSS,文档连接https://tailwindcss.com/docs/guides/vite。


执行完上述命令后,继续执行下一条命令。
运行 npx tailwindcss init -p。
将 tailwind.config.js 文件按照以下方式进行修改。
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
请将index.css文件根据以下方式修改。修改完成后,可能会出现未知的@tailwindcss(unknownAtRules)规则警告,但是不用担心,可以忽略这个警告,没有问题。
@tailwind base;
@tailwind components;
@tailwind utilities;
现在TailwindCSS的安装已经完成,请将App.tsx文件适当修改,以确认是否应用了TailwindCSS。
function App() {
return (
<div
className="w-48 h-48 bg-black"
/>
);
}
export default App;


TailwindCSS的安装已完成。下一步是安装twin.macro。
安装 twin.macro
我已参考了以下文章:
https://osu-log.com/archives/975#toc2
首先,安装twin.macro。
yarn add @emotion/react @emotion/styled
yarn add --dev twin.macro @emotion/babel-plugin-jsx-pragmatic babel-plugin-macros tailwindcss -D
接下来在src文件夹中创建GlobalStyles.tsx,并开始编写其内容。
import React from 'react'
import { css, Global } from '@emotion/react'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'
const customStyles = css({
body: {
WebkitTapHighlightColor: theme`colors.purple.500`,
...tw`antialiased`,
// グローバルスタイルをカスタマイズしたいなら、ここに追記していく
},
})
const GlobalStyles = () => (
<>
<BaseStyles />
<Global styles={customStyles} />
</>
)
export default GlobalStyles
接下来,从src/main.tsx中导入创建的GlobalStyles.tsx。
import React from 'react'
import ReactDOM from 'react-dom/client'
import GlobalStyles from './GlobalStyles' // この文を追記
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<GlobalStyles /> // この文を追記
<App />
</React.StrictMode>
)
请编辑vite.config.js文件,将twin.macro插件添加到vite中。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({
babel: {
plugins: [
'babel-plugin-macros',
[
'@emotion/babel-plugin-jsx-pragmatic',
{
export: 'jsx',
import: '__cssprop',
module: '@emotion/react',
},
],
[
'@babel/plugin-transform-react-jsx',
{ pragma: '__cssprop' },
'twin.macro',
],
],
},
}),
],
esbuild: {
logOverride: { 'this-is-undefined-in-esm': 'silent' }
},
});
最后进行Typescript的设置。创建src/types/twin.d.ts文件,并写入以下内容。
import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import { CSSInterpolation } from '@emotion/serialize'
import styledImport from '@emotion/styled'
declare module 'twin.macro' {
// The styled and css imports
const styled: typeof styledImport
const css: typeof cssImport
}
declare module 'react' {
// The css prop
interface HTMLAttributes<T> extends DOMAttributes<T> {
css?: CSSInterpolation
tw?: string
}
// The inline svg css prop
interface SVGProps<T> extends SVGProps<SVGSVGElement> {
css?: CSSInterpolation
tw?: string
}
}
在tsconfig.json文件中添加以下内容。
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react" << この一行を追記
},
"include": ["src"],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
完成了twin.macro的配置。最后,确认twin.macro是否正确应用了。
import tw, { css } from "twin.macro";
import "./App.css";
function App() {
return (
<div
tw="w-48 h-48 bg-black"
css={css`
box-shadow: 10px 5px 5px red;
`}
></div>
);
}
export default App;

我希望能够充分利用React,以及当我有一些想尝试或想制作的东西时,能够更好地与它相处。感谢那些已经实践过这些步骤的人辛苦了。