Vite+React+SCSS+PostCSS+Zustand+React Router+ESlint+Prettier+Ant Design
1.初始化项目
npm create vite@latest <project-name>
2.安装默认依赖
npm install
3.SCSS
npm install sass -D
npm install @types/node
新建styles文件夹,
src/styles
,新建base.scss
和global.scss
文件修改main、App样式文件后缀与引用
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/styles/global.scss" as *;'
}
}
}
})
4.PostCSS
git:[@github/postcss/postcss]
npm install tailwindcss cssnano autoprefixer postcss-preset-env -D
tailwindcss:本质上是一个工具集,包含了大量类似
flex
、pt-4
、text-center
以及rotate-90
等工具类,可以组合使用并直接在 HTML 代码上实现任何 UI 设计。cssnano:为你的 CSS 文件做多方面的的优化, 以确保最终生成的文件 对生产环境来说体积是最小的。
autoprefixer:一个后处理CSS的工具,它使用Can I Use的数据来决定给CSS选择器添加什么前缀。这意味着开发者只需编写标准的CSS代码,Autoprefixer会根据目标浏览器的需要自动添加相应的前缀。
postcss-preset-env:整合了很多的常用插件到一起,并帮你完成了基本的配置。
书写配置文件 postcss.config.js
和 tailwind.config.js
// postcss.config.js
export default {
plugins: {
autoprefixer: {
//css兼容前缀
overrideBrowserslist: [
'Android 4.1',
'ios 7.1',
'Chrome >31',
'not ie <=11', //不考虑IE浏览器
'ff >= 30', //仅新版本用'ff >= 30
'>1%', //全球统计有超过1%的使用了使用'> 1%'
'last 2 version' //所有主流浏览器最近2个版本
],
grid: true //开启grid布局的兼容(浏览器IE除外其它都能兼容grid,可以关闭开启)
},
'postcss-import': {},
cssnano: {},
'postcss-preset-env': {
/* use stage 3 features + css nesting rules */
stage: 3,
features: {
'nesting-rules': true
}
}
}
}
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
theme: {
colors: {
black: '#1f1f1f',
white: '#f0f0f0'
},
extend: {}
},
plugins: []
}
引入tailwindcss
// src/styles/base.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
:root,
html,
body {
margin: 0;
padding: 0;
font-size: 16px;
font-family: 'PingFangSC-Medium';
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html,
body,
#root {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
解决VS Code对于 @tailwind
报错 Unknown at rule @tailwind
// .vscode/settings.json
{
"css.customData": [".vscode/tailwindcss.json"]
}
// .vscode/tailwindcss.json
{
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
}
]
},
{
"name": "@apply",
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#apply"
}
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
}
]
}
]
}
5.全局状态管理——Zustand
git:[@github/pmndrs/zustand]
npm install zustand
书写模版Store文件
// src/store/base.ts
import { create } from 'zustand'
type State = {
counter: number
}
type Action = {
increment: () => void
decrement: () => void
}
export const useStore = create<State & Action>((set) => {
return {
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 }))
}
})
App组件使用
import { useStore } from './store/base'
function App() {
const counter = useStore((state) => state.counter)
const increment = useStore((state) => state.increment)
const decrement = useStore((state) => state.decrement)
return (
<div className='flex flex-col h-full w-full justify-center items-center gap-2'>
<div className='text-3xl font-bold'>{counter}</div>
<button className='w-32 px-2 py-1 border-2' onClick={increment}>
+1
</button>
<button className='w-32 px-2 py-1 border-2' onClick={decrement}>
-1
</button>
</div>
)
}
export default App
6.路由——React Router
git:[@github/remix-run/react-router]
npm install react-router-dom
初始化路由文件
// src/routes/index.tsx
import { lazy } from 'react'
import { createBrowserRouter, RouteObject, RouterProvider } from 'react-router-dom'
const Home = lazy(() => import('@/pages/Home'))
const routes: RouteObject[] = [
{
path: '/',
element: <Home />
}
]
// 创建路由
const router = createBrowserRouter(routes)
// 导出路由
const Routes = () => <RouterProvider router={router} />
export default Routes
改写 main.tsx
文件,书写Home组件
// src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './styles/base.scss'
import Routes from './routes/index.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Routes />
</StrictMode>
)
// src/pages/Home/index.tsx
import { useStore } from '@/store/base'
function Home() {
const counter = useStore((state) => state.counter)
const increment = useStore((state) => state.increment)
const decrement = useStore((state) => state.decrement)
return (
<div className='flex flex-col h-full w-full justify-center items-center gap-2'>
<div className='text-3xl font-bold'>{counter}</div>
<button className='w-32 px-2 py-1 border-2' onClick={increment}>
+1
</button>
<button className='w-32 px-2 py-1 border-2' onClick={decrement}>
-1
</button>
</div>
)
}
export default Home
7.代码格式化校验——ESlint、Prettier
npm install prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-react -D
// .eslintrc.cjs
module.exports = {
//使用微信的某些能力时,导入min.js后使用/^wx\..*/报错的解决。
globals: { wx: 'readonly' },
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended', // 'plugin:vue/vue3-essential',
'plugin:prettier/recommended',
'plugin:react/jsx-runtime' // 'eslint-config-prettier'
],
overrides: [
{
env: {
node: true
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script'
}
}
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: ['@typescript-eslint', 'react', 'prettier'],
rules: {
'prettier/prettier': 'error',
'arrow-body-style': 'off',
'prefer-arrow-callback': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' }
]
},
settings: {
react: {
version: 'detect'
}
}
}
// .eslintrc.json
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "react", "react-refresh"],
"rules": {
"@typescript-eslint/no-unused-vars": [
"error",
{ "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }
],
"react-refresh/only-export-components": [
"warn",
{ "allowConstantExport": true }
]
}
}
// .prettierrc.json
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none",
"endOfLine": "auto"
}
8.UI组件库——AntD
git:[@github/ant-design/ant-design]
npm install antd --save
// src/pages/Home/index.tsx
import { useStore } from '@/store/base'
import { Button } from 'antd'
function Home() {
const counter = useStore((state) => state.counter)
const increment = useStore((state) => state.increment)
const decrement = useStore((state) => state.decrement)
return (
<div className="flex flex-col h-full w-full justify-center items-center gap-2">
<div className="text-3xl font-bold">{counter}</div>
<div>
<Button onClick={increment}>+1</Button>
<Button onClick={decrement}>-1</Button>
</div>
</div>
)
}
export default Home
9.优化篇(非必要、仅参考)
vite.config.ts优化
npm install terser
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { fileURLToPath, URL } from 'node:url'
// https://vitejs.dev/config/
export default defineConfig({
server: {
// dev环境端口号
port: 8000,
// 反向代理
proxy: {
'/api': {
target: 'http://127.0.0.1:9000',
changeOrigin: true,
rewrite: (path) => path, // 地址转换
headers: {} // 转发请求头
}
}
},
plugins: [react()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/styles/global.scss" as *;'
}
}
},
build: {
target: 'modules', //浏览器兼容性modules|esnext
sourcemap: false, //构建后是否生成source map文件
minify: 'terser', // 混淆器,terser构建后文件体积更小
// outDir: envConfig.VITE_OUTPUT_DIR, //指定输出文件包名
outDir: 'dist',
assetsDir: 'assets', // 指定生成静态资源的存放路径
chunkSizeWarningLimit: 1500, //警报门槛,限制大文件大小B为单位
assetsInlineLimit: 4096, //小于此阈值的导入或引用资源将内联为base64编码,以避免额外的http请求,设置为0可以完全禁用此项
// 清除console和debugger(minify: 'terser',)设置后这个terserOptions才有用
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
//自动分割包名输出 chunkSizeWarningLimit 配置大小
chunkFileNames: 'js/[name]-[hash].js', //入口文件名
entryFileNames: 'js/[name]-[hash].js', //出口文件名位置
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', //静态文件名位置
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
}
}
}
}
})
vite-plugin-inspect
git:[@github/antfu-collective/vite-plugin-inspect]
检查 Vite 插件的中间状态。用于调试和编写插件。
npm i -D vite-plugin-inspect
import Inspect from 'vite-plugin-inspect'
export default defineConfig({
...,
plugins: [
Inspect({
build: true,
outputDir: '.vite-inspect'
}),
...
],
...,
})
SVG优化
rollup-plugin-visualizer
vite打包可视化工具
git:[@github/btd/rollup-plugin-visualizer]
npm i rollup-plugin-visualizer -D
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
...,
plugins: [
...,
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'buildStats.html'
}),
...
],
...,
})
评论区