前端构建工具vite进阶系列(三) -- 静态资源与css模块化的处理
前言
上一章前端构建工具vite进阶系列(二) -- vite的依赖预构建与配置文件相关处理讲解了vite的依赖预构建与配置文件相关处理,能够让你使用vite去开发项目的时候,更加得心应手,这一章我们将一起来探索一下vite对静态资源以及css模块化相关的处理吧。
vite是如何去识别文件的
我们来回忆一下在webpack中,是怎么去读取文件的呢?是不是通过loader,通过各种loader去读取各种文件,比如css-loader、style-loader处理css文件。因为webpack他所遵循的是CommonJS规范,并且他只能够识别js文件,所以需要各种loader来做代码转换,loader的本质就是一个函数,最后返回的是一段可执行的JavaScript代码就可以了,但是vite呢?我们来研究一下。
- 新建
index.css文件,在index.js中引入import 'index.css'
html, body {
width: 100%;
height: 100%;
background-color: red;
}
效果:
我们发现了,在head标签里面新建了一个style标签,.css文件里里面的内容,都被写到了标签里面。
大概我们能猜到,vite对css文件的处理,也是通过创建一个style标签,在页面引入样式文件这样子处理的。
但是vite不同的是会把css文件转化为js脚本文件,设置Content-Type:"text/javascript"来告知,浏览器应该以JavaScript的方式来解析css脚本。这样做的好处有三点:
- 用于
热更新。 - 用于
css模块化。 - 去除了第三方工具对
css的处理,提高了编译性能。
所以vite应该是在本地开发服务器中,把对资源文件的处理,转化为浏览器对资源文件的解析,比如:
- 构建本地开发服务器
- 设置相应头:
Content-type:"text/javascript",「.vue文件」 - 让浏览器以JavaScript的方式来解析
.vue文件。
vite对css模块化的处理
我们知道webpack对css文件的热更新依赖于loader自身的热更新,但是vite里面没有实现loader机制,这一点我将会在后期热更新那一章讲到。那么这里主要来讲一下vite对css模块化处理吧。
- 为什么会出现
css模块化?- 其根本原因就是为了解决协同开发,
类名,id等冲突引起样式覆盖的问题。
- 其根本原因就是为了解决协同开发,
- 如何解决?
- 比如css模块化,模块化策略表示,每一个
css文件为单独的一个模块,具有单独模块的作用域,这样能够保证我使用的类名的唯一性,独立性。 - 我们来依次建立两个文件来证明一下,
kk.module.css与bb.mocule.css。
- 比如css模块化,模块化策略表示,每一个
.l{ // 两个文件依次写上这样的类名
font-size: 100px;
color: red
}
// kk.js
import kkModuleCss from './kk.module.css'
console.log(kkModuleCss);
const ele = document.createElement('div');
ele.className = kkModuleCss.l;
ele.innerHTML = '我是kk';
document.body.append(ele)
// bb.js
import bbModuleCss from './bb.module.css'
console.log(bbModuleCss);
const ele = document.createElement('div');
ele.className = bbModuleCss.l;
ele.innerHTML = '我是bb';
document.body.append(ele)
效果:

- 我们发现了我们写的样式会被处理成
key:value的形式,以类名作为键名,处理后的类名作为键值。

- 真实的类名会被替换成处理后的键值。

- 我们发现在
style中也会出现替换后的内容。
所以cssModule的原理也就是很简单了。
module.css是一种约定,表示要开启css模块化。- 类名替换,比如
'.l'会被替换成'_l_1jq3b_1'。 - 创建映射对象,比如
{l: "_l_1jq3b_1"}。 - 将替换后的样式内容创建
style标签,插入到head中。 vite将module.css文件内容删除,把新内容替换成js脚本,用于热更新。
less或者scss的模块化处理
less与scss模块化处理,跟css一样,都会创建一个映射对象,创建style,插入内容,插入head,这里不再复述。
less与scss去编译文件,就是把less或者scss写法,变成css写法。
用户配置大于默认,vite中应该怎么去做
import { defineConfig } from 'vite';
import postcssPresetEnv from 'postcss-preset-env';
export default defineConfig({
...
envPrefix:'ENV_', // 配置环境变量前缀
css:{
modules:{
localsConvention:"camelCase", // 展示处理之后的key,
scopeBehaviour:'local', // 配置的模块化还是全局还是局部
generateScopedName:'[name]_[local]_[hash:5]' // 类名生成规则
hashPrefix:'xxxxx', // 根据哈希加老类名生成文件新类名
globalModulePaths:[] // 不想参与css格式化的文件路径
},
preprocessorOptions:{
less:{
// 在这里写的参数为key:value形式,会作为命令行参数,传递到预处理器编译的时候执行
// 比如 npx less --math="strict" index.module.css
// 就需要在这里配置
math:"strict",
globalVars:{
mainColor:"red" //全局变量
}
// 更多请查看 https://lesscss.org/usage/#less-options-include-paths
},
scss:{
// 命令行追加参数
...
}
},
devSourcemap:true, // 开启css文件索引,以便于报错的时候能够找到源码位置
postcss:{
// postcssPresetEnv插件可以帮我们实现自动补全,语法降级等功能
plugins:[postcssPresetEnv()]
// 关于postcss文章请查看https://github.com/postcss/postcss/blob/main/docs/README-cn.md
}
}
})
关于css模块化,就说这么多,那么vite是怎么去处理静态资源的呢?来一起探索下。
静态资源处理
在webpack中,比如图片,视频,需要通过image-loader、file-loader等来加载处理,但是vite对静态资源是开箱即用的,除了svg资源,那么我们来研究一下他是怎么开箱即用的呢。
- 关于图片,我们只需要像往常一样写就可以了。比如我们生成一个
img标签:
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中引入执行
效果:

- 关于
json文件的处理
// index.json
{
"name":"YiXIZHISHI",
"age":18
}
// index.js
import indexJson from './index.json';
console.log(indexJson)
for(let i in indexJson){
const e = document.createElement('p');
e.innerHTML = `${i}:${indexJson[i]}`;
document.body.append(e)
}


这样跟一般的导入的话区别是这样导入是一个对象,不用vite的话,他将是一个字符串。但是vite还支持按需导入属性,有利于tree-shaking,比如:
import {name,age} from './index.json';
console.log(`name:${name}, age:${age}`);

如果不懂tree-shaking的话,请移步 >>> 重学webpack系列(九) -- webpack的高级特性与前端性能优化
- 关于
svg文件的处理
vite对svg也是开箱即用的,但是svg与img不同,这得追溯一下我们为什么要使用svg?为了方便修改样式对不对?首先svg可以按照普通图片那样加载没问题,也可以按照svg方式加载。
- 按照
图片加载:import indexSvg from '@assets/index.svg?url',拿到的是相对路径。

- 按照
svg加载:import indexSvgRaw from '@assets/index.svg?raw',拿到的是svg字符串。
变成了svg,我们就可以去改变颜色等属性了。
路径别名配置
- 场景:在解决相对路径造成的代码不雅观的同时,能够防止路径出错,让你不再
../../。vite提供了路径别名来解决这样的问题。 - 实现:在
vite.base.config.js里面配置resolve属性。
export default defineConfig({
...
resolve:{
alias:{
"@":path.resolve(__dirname, './src'),
"@assets":path.resolve(__dirname, './src/assets'),
// 指定@符的路径,比如 import xx from '@component/index.vue'
"@component":path.resolve(__dirname, './src/component')
}
}
})
vite在生产环境对静态资源的处理
首先我们来执行一下npm run build,这样在项目根目录生成了一个dist文件,长这样:

跟webpack对比一下,文件名,文件内容都给我们进行了处理,比如文件名的替换(hash:8),内容的压缩,tree-shaking,我们看一下index.html文件。

关于资源的路径处理成了绝对路径,以上种种vite在生产环境是不会去处理的而是交给rollup去全权处理,所以我们需要告诉rollup的一些配置规则。
build的配置
export default defineConfig({
...
build:{ // 生产环境的配置
rollupOptions:{ // 给rollup的配置
output:{ // 输出
assetFileNames:"[name]-[hash].[ext]"
}
},
assetsInlineLimit:"1024", // 大于1024kb资源,打包成base64,
outDir:"build", // 输出目录
assetsDir:"static" // 静态目录
// 更多请查看https://rollupjs.org/configuration-options/#output-assetfilenames
// vite配置文档https://cn.vitejs.dev/config/build-options.html#build-rollupoptions
}
})
总结
本章节讲述了vite对css模块化静态资源的一些处理,基本上都是开箱即用的,在开发环境只是这样,在生产环境vite并没有做更多的,只是全权交给rollup去做,这到底是提升还是提升呢?rollup处理与webpack的处理又有什么区别呢?下一章 >>> 前端构建工具vite进阶系列(四) -- 插件系统让vite变得更强大
转载自:https://juejin.cn/post/7206909221806981175