css 模块化处理
vite 处理 css 的方式
在webpack
中,是通过 css-loader
、style-loader
来处理css
文件,那在 vite 中没有实现 loader
机制,那它是如何处理 css 的呢?
我们先来举个例子:
js
// index.css
body {
background-color: aliceblue;
}
//main.js
import './index.css';
然后我们启动 vite 服务器:

我们发现了在head
标签里面新建了一个style
标签,.css
文件里里面的内容,都被写到了标签里面。 大概我们能猜到,vite
对css
文件的处理,也是通过创建一个style
标签,在页面引入样式文件这样子处理的。所以vite
天生就支持对 css
的直接处理。
但需要注意的是:vite
会把 css
转化为 js
,设置 Content-Type:"text/javascript"
来告知浏览器应该以 JavaScript
的方式来解析 css
。

这样做的好处有三点:
- 用于
热更新
。 - 用于
css
模块化。 - 去除了第三方工具对
css
的处理,提高了编译性能
。
vite 对 css 的模块化处理
- 为什么模块化?
- 其根本原因就是为了解决协同开发,
类名
,id
等冲突引起样式覆盖的问题。
- 其根本原因就是为了解决协同开发,
- 如何解决?
- 让每一个
css
文件为单独的一个模块,具有单独模块的作用域,这样能够保证我使用的类名的唯一性,独立性。
- 让每一个
比如:我们创建两个模块化的css:a.module.css
、b.module.css
js
// a.module.css
.wrapper {
font-size: 20px;
color: blue
}
// b.module.css
.wrapper {
font-size: 100px;
color: red
}
//main.js
import AModuleCss from './a.module.css'
import BModuleCss from './b.module.css'
const ele1 = document.createElement('div');
ele1.className = AModuleCss.wrapper;
ele1.innerHTML = 'aaaaaa';
document.body.append(ele1)
const ele2 = document.createElement('div');
ele2.className = BModuleCss.wrapper;
ele2.innerHTML = 'bbbbb';
document.body.append(ele2)
我们看页面:

我们发现,同样的类名,却只对自己作用域下的元素生效
并且,样式会被处理成 key: value
的形式,以类名作为键名,处理后的类名作为键值

真实的类名会被替换成被处理后的类名:

css 模块化的原理
- 对 css 文件取名为
xxx.module.css
(module是一种约定, 表示需要开启css模块化) - 他会将你的所有类名进行一定规则的替换(将footer 替换成 _footer_i22st_1)
- 同时创建一个映射对象 { footer: "_footer_i22st_1" }
将替换过后的内容塞进 style 标签里然后放入到 head 标签中
(能够读到index.html的文件内容)- 将 xx.module.css 内容进行全部抹除,
替换成JS脚本
- 将创建的映射对象在脚本中进行默认导出
vite 配置 css (模块化处理)
js
import { defineConfig } from 'vite';
import postcssPresetEnv from 'postcss-preset-env';
export default defineConfig({
...
envPrefix:'ENV_', // 配置环境变量前缀
css:{
modules:{
// 展示模块化处理之后的key的展示形式,
localsConvention:"camelCase",
// 配置当前的模块化行为是模块化还是全局化
// (有hash就是开启了模块化的一个标志, 因为他可以保证产生不同的hash值来控制我们的样式类名不被覆盖)
scopeBehaviour:'local',
// 生成的类名的规则(可以配置为函数, 也可以配置成字符串规则: <https://github.com/webpack/loader-utils#interpolatename>)
generateScopedName:'[name]_[local]_[hash:5]'
// 根据哈希加老类名生成文件新类名
hashPrefix:'xxxxx',
// 不想参与 css 模块化的文件路径
globalModulePaths:[]
}
})
vite 配置 css (预处理器配置)
js
import { defineConfig } from 'vite';
import postcssPresetEnv from 'postcss-preset-env';
export default defineConfig({
...
envPrefix:'ENV_', // 配置环境变量前缀
css:{
// 模块化处理配置
modules:{},
// 预处理器配置
preprocessorOptions: {
// 处理 less
less: {
math: "always",
// 全局变量
globalVars:{
mainColor:"red"
}
// 更多请查看 https://lesscss.org/usage/#less-options-include-paths
},
// 处理 sass
scss: {
},
// 开启css文件索引,以便于报错的时候能够找到源码位置
devSourcemap:true,
postcss: {
// postcssPresetEnv插件可以帮我们实现自动补全,语法降级等功能
plugins:[postcssPresetEnv()]
}
}
})
静态资源处理
vite
对静态资源是开箱即用的
处理图片
关于图片,我们只需要像往常一样写就可以了。比如我们生成一个img
标签:
js
// a.js
import indexImg from './assets/index.jpg'
const loadImg = ()=>{
const img = document.createElement('img');
img.src = indexImg
img.setAttribute('width','80%')
document.body.append(img)
}
export default loadImg // 在index.js中引入执行
//index.js
import loadImg from "./counter";
loadImg();
结果如下:

处理 svg
svg
可以按照普通图片
那样加载没问题,也可以按照svg
方式加载。
- 按照
普通图片
加载,即在 import 时,直接引入或者后面带上?url
js
// a.js
import indexSvg from './assets/about.svg?url'
//或者
// import indexSvg from './assets/about.svg'
const loadImg = ()=>{
const img = document.createElement('img');
img.src = indexSvg
img.setAttribute('width','80%')
document.body.append(img)
}
export default loadImg // 在index.js中引入执行
// index.js
import loadImg from "./a";
loadImg();
结果如下:

但是以图片方式
加载 svg
的缺点在于:不能修改它的颜色,所以 svg
一般以下面这种方式使用
- 按照
svg
加载,后面带上?raw
js
// a.js
import indexSvg from './assets/about.svg?raw'
const loadImg = ()=>{
document.body.innerHTML = indexSvg
}
export default loadImg // 在index.js中引入执行
// index.js
import loadImg from "./a";
loadImg();
结果如下:

变成了svg
,我们就可以去改变颜色等属性了
路径处理
- 在
vite.base.config.js
里面配置resolve.alias
属性。和webpack很像
js
export default defineConfig({
...
resolve:{
alias:{
"@":path.resolve(__dirname, './src'),
"@assets":path.resolve(__dirname, './src/assets'),
"@component":path.resolve(__dirname, './src/component')
}
}
})
resolve.alias
的原理:
比如在导入资源(比如图片)时,对于后端来说就是要去请求和加载这个静态资源文件,所以 Vite 服务器在后端路由中,先将请求的路径结合 vite.config.js
配置,将请求路径进行字符串替换,也就是将 @
替换成 path.resolve
方法生成后的绝对路径,通过这个绝对路径找到对应的资源再将结果返回到浏览器。