vue如何提取异步组件内部的CSS?

Q:vue如何提取异步组件内部的CSS?
使用vue-cli webpack模板生成代码,项目结构如下图:
clipboard.png
新增test.vue组件,router/index.js代码如下:

import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
// import Test from '@/components/Test'
const HelloWorld = resolve => require(['@/components/HelloWorld'], resolve)
const Test = resolve => require(['@/components/Test'], resolve)

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
    {
      path: '/test',
      name: 'test',
      component: Test
    }
  ]
})

test.vue代码如下:

<template>
    <div>Demo</div>
</template>
<script>
    export default {
        data(){
            return {

            }
        },
        methods:{

        },
        mounted(){

        }
    }
</script>

<style scoped>
    div {
        color: red;
    }
</style>

打包之后的dist会生成不同模块加载的js文件,遗憾的是,.vue文件中的css,并没有按照希望的效果打包提取到单独的CSS文件夹中,而是仍然混合在JS里面的,如图:
clipboard.png

结果测试,组件不使用异步加载,router/index.js代码如下:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Test from '@/components/Test'
// const HelloWorld = resolve => require(['@/components/HelloWorld'], resolve)
// const Test = resolve => require(['@/components/Test'], resolve)

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
    {
      path: '/test',
      name: 'test',
      component: Test
    }
  ]
})

打包之后,可以达到预定的效果:如图:

clipboard.png

Q:感觉CSS混合在JS中有点印象网页加载性能,如何提取异步组件中的CSS到单独的CSS文件夹中?

回答:

理论上做不到,因为异步组件是使用 jsonp 的方式加载,而如果单独提取出一个 css 文件,则由于 extractTextPlugin 的作用机制,在生成的 chunk js 文件中没有留下任何 css 文件的信息,webpack 运行时异步加载函数不知道该文件的存在,从而也不可能知道如何单独加载这个 css 文件(还要单独实现一个异步加载 css 文件的方法)。

webpack 编译阶段对入口文件使用 extractTextPlugin 提取 css 之后,是(通过 extractTextPlugin 的输出)知道 css 文件的存在,并能通过 HtmlWebpackPlugin 将之插入到 html 文件中的。

简言之,build 的时候是编译阶段,webpack 知道相关信息并能正确处理,异步组件的加载是运行阶段,这时候运行时的代码已经无从得知相关编译信息了,因此异步加载的组件无法提取 css 内容生成单独的文件。

建议将相关的 css 写到一个单独的 test.css 文件中,然后使用 <style src='test.css'> 放到 app.vue 里(注意不要加 scoped),这样就会在 app.[hash].css 中包含这部分 css 了。单独写一个 .css 文件便于代码维护。

为了防止 css 类名冲突,可以在 css 的每个选择子前面加一个 [v-test-component] (含空格)属性选择子前缀,然后将 test.vue 的根元素写成 <div v-test-component></div>。使用 less 或者 sass 统一加前缀可能更为简洁。

[v-test-component] {
  .class-a { color: red; }
  .class-b { color: green; }
  /* other styles */
}

回答:

vue-cli只在production环境下利用插件ExtractTextPlugin抽取css

回答:

production环境默认是会使用ExtractTextPlugin将所有样式都提取到一起并且压缩,但是如果想改为将样式打包进js只需更改一下配置即可,vue-cli生成的项目,在webpack.prod.config.js中,ExtractTextPluginallChunks设为false,就会将样式打包进js,但是这样会增加打包文件的体积,不过能够减少首屏的文件体积,因为这样只需加载首屏页面引用到的样式数据。

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注