vue-loader原理学习

1,789 阅读2分钟

1.vue-loader 的使用

相关的loader:

  • vue-loader
  • vue-style-loader
  • vue-template-compiler 用于编译模板
  • css-loader
  • 如果使用css扩展语言,可能还需要导入:
  • sass-loader/less-loader/url-loader等 vue-loader的🌰使用例子
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { VueLoaderPlugin } = require('vue-loader')
const isProduction = process.env.NODE_ENV === 'production'
const extractLoader = {
    loader: MiniCssExtractPlugin.loader,
    options: {
        publicPath: '../',
        hmr: process.env.NODE_ENV === 'development'
    },
}
const cssExtractplugin = new MiniCssExtractPlugin({
    filename: '[name].css',
    chunkFilename: '[id].css',
    ignoreOrder: false
})
const webpackConfig = {
    entry: {...},
    output: {...},
    optimization: {...},
    resolve: {...},
    modules: {
        rules: [{
            test: /.vue$/,
            loader: 'vue-loader'
        }, {
            test: /.css$/,
            oneOf: [{
                resourceQuery: /?vue/,
                use: [isProduction ? extractLoader  : 'vue-style-loader', 'css-loader']
            }, {
                use: [isProduction ? extractLoader  : 'style-loader', 'css-loader']
            }]
        },
        ...
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        isProduction ? cssExtractplugin : ''
    ]
    
}

2.vue-loader 工作原理

通过webpack通过vue-loader插件,把.vue文件转化为js。

  • 注意里面包含3个部分: template、script、styles vue-loader 的工作流程
  • template : 通过 vue-template-compiler 生成 ast 转 render,所有的render函数都会push到 staticRenderFns。
  • script :返回的配置项对象 scriptExports。
  • styles :通过 css-loader、vue-style-loader, 添加到 head 中, 或者通过 css-loader、MiniCssExtractPlugin 提取到一个公共的css文件中。
  • 使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回构建vue组件需要的配置项对象 - options, 即 {data, props, methods, render, staticRenderFns...} 。

代码:

// 从 template区域块 获取 render、 staticRenderFns 方法
import { render, staticRenderFns } from "./App.vue?vue&type=template&id=89kjg85f&scoped=true&"
// 从 script区域块 获取 组件的配置项对象
import script from "./App.vue?vue&type=script&lang=js&"
export * from "./App.vue?vue&type=script&lang=js&"
// 获取 styles区域块的内容
import style0 from "./App.vue?vue&type=style&index=0&lang=css&"
// 获取 styles(scoped)区域块的内容
import style1 from "./App.vue?vue&type=style&index=1&id=89kjg85f&scoped=true&lang=css&"

/* normalize component */
import normalizer from "!../node_modules/_vue-loader@15.7.1@vue-loader/lib/runtime/componentNormalizer.js"
// 返回构建组件需要的配置项对象, 包含 data、props、render、staticRenderFns 等
var component = normalizer(
  script,
  render,
  staticRenderFns,
  false,
  null,
  "89kjg85f",
  null
  
)

component.options.__file = "src/App.vue"
// 输出组件完整的配置项
export default component.exports

3.css scoped原理

当.vue 文件中的 style 标签有scoped 属性时,它的 css 样式 只作用于当前 组件中的元素。

css scoped 的 工作流程 如下:

  1. 使用 vue-loader 处理.vue文件,根据.vue文件 的 请求路径和文件内容,生成 .vue 文件的hash值, 如:89kjg85f;
  2. 如果 .vue 文件 的 某一个style 标签 有 scoped 属性,为.vue 文件 生成一个 scopedId,scopedId 的格式为 data-v-hash, 如:data-v-89kjg85f;
  • 使用 vue-loader 从.vue 文件 中获取 style区域块(scoped) 的 样式内容(字符串) ;
  • 如果使用了 less 或者 sass,要使用less-loader或者sass-loader 处理 样式内容,使样式内容 变为 浏览器可识别的css样式;
  • 然后使用 PostCSS 提供的 parser 处理 样式内容,为 样式内容中的每一个 css选择器添加[data-v-hash];
  • 再使用 css-loader;最后使用 style-loader把 css 样式添加到 head 中
  • 或者通过 miniCssExtractPlugin 将 css 样式 提取一个公共的 css 文件中。
  1. 通过 normalizer 方法返回 完整的组件配置项 options, options 中有属性 _scopeId, 如 _scopedId: data-v-89kjg85f;

  2. 使用 组件配置项 options 构建组件实例,给组件中每一个dom元素 添加属性: data-v-hash。

  3. 经历上述过程,style(scoped)中的样式就变成了组件的私有样式。