前端构建工具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