前言
我们公司前端内部在开发vue形成了一个开发习惯,大家在写css的时候都会提取成单独的文件,然后再导入到需要使用这个css的文件中,但是css导入到vue文件中大体分为两种方式,一个是在style标签导入,一个是在script标签导入,下面我们就来分析下这两种导入方式的差异。
style标签导入
看一个示例,只是一个为了说明问题的示例
// 父组件 App.vue
<template>
<div class="parent">
Parent
<Child />
</div>
</template>
<style>
@import url('@/assets/main.css');
</style>
// 子组件 Child.vue
<template>
<div class="child">
Child
</div>
</template>
<style>
@import url('@/assets/main.css');
</style>
// main.css内容
.parent {
color: red;
}
.child {
color: green;
}
乍一看这样导入没什么问题,而且页面样式也都能正常显示。但是通过谷歌的Devtool就能看出一些端倪。
哎,奇怪怎么class类会出现了两份。
不急 咱们来分析下原因
看下App.vue最终运行被编译的内容
发现被导入的main.css被处理成了一个
虚拟文件,再来看下这个文件实际返回的内容
这个文件把style标签里面导入的main.css文件处理成了一个字符串变量
__vite__css,然后通过内部的__vite__updateStyle方法把这些css通过style标签的方式插入到文档中。
同理Child.vue引入的css也被同样的处理了
正因为同样的一份css被处理了两次并且都通过内部方法__vite__updateStyle把css通过style标签插入到文档中,才导致一个parent类出现了两次。
开发环境中这个类被处理了两次,最终生产环境这个类也会被处理两次,导致最终打包生成的css资源变大
说到这不得不提一嘴@vue/compiler-sfc插件在处理vue单文件组件时的基本原理,它会把一个vue文件处理成3个部分template、script、style,然后分别将每个部分交给对应的预处理器处理生成纯净的css或者javascript,以后再交回给@vue/compiler-sfc统一处理
script标签导入
// 父组件 App.vue
<template>
<div class="parent">
Parent
<Child />
</div>
</template>
<script>
import '@/assets/main.css';
</script>
// 子组件 Child.vue
<template>
<div class="child">
Child
</div>
</template>
<script>
import '@/assets/main.css';
</script>
再来看看App.vue加载的css资源有什么变化
Child.vue加载的css资源
不难发现这两个文件引入的css文件地址变成了一个,那我们页面引用的css也就只有一份了,相同的类名也不会出现多个
最终构建后生成的文件也不会包含重复的css样式
总结
弄清楚这两种导入css文件的区别啦,如果不是提别需要scoped,为了降低最终构建生成的包体积,所以我们优先考虑在script标签里面导入css。