zoukankan      html  css  js  c++  java
  • Vue Loader

    介绍

    • 允许为 Vue 组件的每个部分使用其它的 webpack loader,例如在 <style> 的部分使用 Sass 和在 <template> 的部分使用 Pug(模板引擎)
    • 允许在一个 .vue 文件中使用自定义块,并对其运用自定义的 loader 链;

    起步

    • Vue Loader 的配置和其它的 loader 不太一样。除了通过一条规则将 vue-loader 应用到所有扩展名为 .vue 的文件上之外,请确保在你的 webpack 配置中添加 Vue Loader 的插件
    // webpack.config.js
    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    
    module.exports = {
      mode: 'development',
      module: {
        rules: [    // 应该是自上而下依次处理
          {
            test: /\.vue$/,
            loader: 'vue-loader'
          },
          // 它会应用到普通的 `.js` 文件
          // 以及 `.vue` 文件中的 `<script>` 块
          {
            test: /\.js$/,
            loader: 'babel-loader'
          },
          // 它会应用到普通的 `.css` 文件
          // 以及 `.vue` 文件中的 `<style>` 块
          {
            test: /\.css$/,
            use: [
              'vue-style-loader',    // 用来提供css的热重载
              'css-loader'    // 用来处理css中的资源路径为模块,同时支持CSS Modules(<style module>)
            ]
          }
        ]
      },
      plugins: [
        // 请确保引入这个插件来施展魔法。它的职责是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,如果你有一条匹配 /\.js$/ 的规则,那么它会应用到 .vue 文件里的 <script> 块。
        new VueLoaderPlugin()
      ]
    }
    
    • 选项参考?是vue loader的选项吗?

    处理资源路径

    • 当 Vue Loader 编译单文件组件中的 <template> 块时,它也会将所有遇到的资源 URL 转换为 webpack 模块请求。
    <img src="../image.png">
    // 编译成
    createElement('img', {
      attrs: {
        src: require('../image.png') // 现在这是一个模块的请求了
      }
    })
    
    • 默认下列标签/特性的组合会被转换,且这些组合时可以使用 transformAssetUrls 选项进行配置的。
    {
      video: ['src', 'poster'],
      source: 'src',
      img: 'src',
      image: 'xlink:href'
    }
    
    • 如果你配置了为 <style> 块使用 css-loader,则你的 CSS 中的资源 URL 也会被同等处理。

    转换规则

    • 如果路径是绝对路径 (例如 /images/foo.png),会原样保留。
    • 如果路径以 . 开头,将会被看作相对的模块依赖,并按照你的本地文件系统上的目录结构进行解析。
    • 如果路径以 ~ 开头,其后的部分将会被看作模块依赖。这意味着你可以用该特性来引用一个 Node 依赖中的资源
    • 如果路径以 @ 开头,也会被看作模块依赖。如果你的 webpack 配置中给 @ 配置了 alias,这就很有用了。所有 vue-cli 创建的项目都默认配置了将 @ 指向 /src。

    相关的 Loader

    • 因为像 .png 这样的文件不是一个 JavaScript 模块,你需要配置 webpack 使用 file-loader 或者 url-loader 去合理地处理它们。通过 Vue CLI 创建的项目已经把这些预配置好了。
      • file-loader 可以指定要复制和放置资源文件的位置,以及如何使用版本哈希命名以获得更好的缓存。此外,这意味着 你可以就近管理图片文件,可以使用相对路径而不用担心部署时 URL 的问题。使用正确的配置,webpack 将会在打包输出中自动重写文件路径为正确的 URL。
      • url-loader 允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数。如果文件大于该阈值,会自动的交给 file-loader 处理。

    使用预处理器

    • style中会根据 lang 特性以及你 webpack 配置中的规则自动推断出要使用的 loader

    Sass

    npm install -D sass-loader node-sass
    
    
    module.exports = {
      module: {
        rules: [
          // ... 忽略其它规则
    
          // 普通的 `.scss` 文件和 `*.vue` 文件中的
          // `<style lang="scss">` 块都应用它
          {
            test: /\.scss$/,
            use: [
              'vue-style-loader',
              'css-loader',
              'sass-loader'
            ]
          }
        ]
      },
      // 插件忽略
    }
    
    • 能够 import 'style.scss' ?

    Sass vs SCSS

    • SCSS是Sass 3引入的新语法,为了向css3靠拢
    • sass-loader 会默认处理不基于缩进的 scss 语法。为了使用基于缩进的 sass 语法,你需要向这个 loader 传递选项:
    // webpack.config.js -> module.rules
    {
      test: /\.sass$/,
      use: [
        'vue-style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            indentedSyntax: true
          }
        }
      ]
    }
    

    共享全局变量

    • sass-loader 也支持一个 data 选项,这个选项允许你在所有被处理的文件之间共享常见的变量,而不需要显式地导入它们:
    // webpack.config.js -> module.rules
    {
      test: /\.scss$/,
      use: [
        'vue-style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            // 你也可以从一个文件读取,例如 `variables.scss` ?
            data: `$color: red;`
          }
        }
      ]
    }
    

    Less

    npm install -D less less-loader
    
    // webpack.config.js -> module.rules
    {
      test: /\.less$/,
      use: [
        'vue-style-loader',
        'css-loader',
        'less-loader'
      ]
    }
    

    Stylus

    npm install -D stylus stylus-loader
    
    // webpack.config.js -> module.rules
    {
      test: /\.styl(us)?$/,
      use: [
        'vue-style-loader',
        'css-loader',
        'stylus-loader'
      ]
    }
    

    PostCSS

    • PostCSS 的配置可以通过 postcss.config.js 或 postcss-loader 选项来完成。postcss-loader 也可以和上述其它预处理器结合使用。
    • Vue Loader v15 不再默认应用 PostCSS 变换。你需要通过 postcss-loader 使用 PostCSS。
    npm install -D postcss-loader
    
    // webpack.config.js -> module.rules
    {
      test: /\.css$/,
      use: [
        'vue-style-loader',
        {
          loader: 'css-loader',
          options: { importLoaders: 1 }
        },
        'postcss-loader'
      ]
    }
    

    Babel

    • Babel 的配置可以通过 .babelrc 或 babel-loader 选项来完成。
    npm install -D babel-core babel-loader
    
    // webpack.config.js -> module.rules
    {
      test: /\.js?$/,
      loader: 'babel-loader'
    }
    

    排除 node_modules

    • 如果你导入一个 node_modules 内的 Vue 单文件组件,它的 <script> 部分在转译时将会被排除在外。
    • 为了确保 JS 的转译应用到 node_modules 的 Vue 单文件组件,你需要通过使用一个排除函数将它们加入白名单:
    {
      test: /\.js$/,
      loader: 'babel-loader',
      exclude: file => (
        /node_modules/.test(file) &&
        !/\.vue\.js/.test(file)    // 正则匹配.vue.js后缀的文件,是因为.vue被vue loader处理后js会生成后缀未.vue.js的js吧
      )
    }
    

    TypeScript

    • TypeScript 的配置可以通过 tsconfig.json 来完成。
    npm install -D typescript ts-loader
    
    // webpack.config.js
    module.exports = {
      resolve: {
        // 将 `.ts` 添加为一个可解析的扩展名。
        extensions: ['.ts', '.js']
      },
      module: {
        rules: [
          // ... 忽略其它规则
          {
            test: /\.ts$/,
            loader: 'ts-loader',
            options: { appendTsSuffixTo: [/\.vue$/] }
          }
        ]
      },
      // ...plugin omitted
    }
    

    pug

    • 模板的处理会稍微有些不同,因为绝大对数 webpack 的模板类 loader,诸如 pug-loader,会返回一个模板函数而不是一个编译好的 HTML 字符串
    • 一个返回原始的 HTML 字符串的 loader,例如 pug-plain-loader
    // .vue中
    <template lang="pug">
    div
      h1 Hello world!
    </template>
    
    // webpack中
    npm install -D pug pug-plain-loader
    
    // webpack.config.js -> module.rules
    {
      test: /\.pug$/,
      loader: 'pug-plain-loader'
    }
    
    • 你还打算使用它在 JavaScript 中将 .pug 文件作为字符串导入,你需要在这个预处理 loader 之后链上 raw-loader
    // webpack.config.js -> module.rules
    {
      test: /\.pug$/,
      oneOf: [    // 规则数组,当规则匹配时,只使用第一个匹配规则。
        // 这条规则应用到 Vue 组件内的 `<template lang="pug">`
        {
          resourceQuery: /^\?vue/,
          use: ['pug-plain-loader']
        },
        // 这条规则应用到 JavaScript 内的 pug 导入
        {
          use: ['raw-loader', 'pug-plain-loader']
        }
      ]
    }
    

    Scoped CSS

    • 当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。它通过使用 PostCSS 来实现以下转换(不是说不再默认使用吗?)
    <style scoped>
    .example {
      color: red;
    }
    </style>
    
    <template>
      <div class="example">hi</div>
    </template>
    
    // 转换为
    <style>
    .example[data-v-f3f3eg9] {
      color: red;
    }
    </style>
    
    <template>
      <div class="example" data-v-f3f3eg9>hi</div>
    </template>
    

    混用本地和全局样式

    • 可以在一个组件中同时使用有 scoped 和非 scoped 样式

    子组件的根元素

    • 使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。

    深度作用选择器

    • 如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符。有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 操作符取而代之
    <style scoped>
    .a >>> .b { /* ... */ }
    </style>
    // 编译为
    .a[data-v-f3f3eg9] .b { /* ... */ }
    

    动态生成的内容

    • 通过 v-html 创建的 DOM 内容不受 scoped 样式影响,但是你仍然可以通过深度作用选择器来为他们设置样式。

    注意事项

    • 当 p { color: red } 是 scoped 时 (即与特性选择器组合使用时) 会慢很多倍。如果你使用 class 或者 id 取而代之,比如 .example { color: red },性能影响就会消除。

    CSS Modules

    • vue-loader 提供了与 CSS Modules 的一流集成,可以作为模拟 scoped CSS 的替代方案。
    • CSS Modules通过对css中选择器的编译,来实现该种选择器在全局中的唯一性

    用法

    • 通过向 css-loader 传入 modules: true 来开启(vue-cli默认开启)
    // webpack.config.js
    {
      module: {
        rules: [
          // ... 其它规则省略
          {
            test: /\.css$/,
            use: [
              'vue-style-loader',
              {
                loader: 'css-loader',
                options: {
                  // 开启 CSS Modules
                  modules: true,
                  // 自定义生成的类名
                  localIdentName: '[local]_[hash:base64:8]'
                }
              }
            ]
          }
        ]
      }
    }
    
    • module 特性指引 Vue Loader 作为名为 $style 的计算属性,向组件注入 CSS Modules 局部对象。然后你就可以在模板中通过一个动态类绑定来使用它了:
    <style module>    // 在你的 <style> 上添加 module 特性
    .red {
      color: red;
    }
    .bold {
      font-weight: bold;
    }
    </style>
    
    <template>
      <p :class="$style.red">    // "red_1VyoJ-uZ"由开启时自定义生成的类名决定
        This should be red
      </p>
    </template>
    

    可选用法

    • 如果你只想在某些 Vue 组件中使用 CSS Modules,你可以使用 oneOf 规则并在 resourceQuery 字符串中检查 module 字符串(vue-cli好像默认开启,只有style拥有module属性才会是模块化样式)
    // webpack.config.js -> module.rules
    {
      test: /\.css$/,
      oneOf: [
        // 这里匹配 `<style module>`
        {
          resourceQuery: /module/,
          use: [
            'vue-style-loader',
            {
              loader: 'css-loader',
              options: {
                modules: true,
                localIdentName: '[local]_[hash:base64:5]'
              }
            }
          ]
        },
        // 这里匹配普通的 `<style>` 或 `<style scoped>`
        {
          use: [
            'vue-style-loader',
            'css-loader'
          ]
        }
      ]
    }
    

    和预处理器配合使用

    • CSS Modules 可以与其它预处理器一起使用
    // webpack.config.js -> module.rules
    {
      test: /\.scss$/,
      use: [
        'vue-style-loader',
        {
          loader: 'css-loader',
          options: { modules: true }
        },
        'sass-loader'
      ]
    }
    

    自定义的注入名称

    • 这时this下会绑定一个名为a得计算属性
    <div :class='a.about'></div>
    
    
    <style module="a">
      /* 注入标识符 a */
    </style>
    

    热重载

    • 当你修改 .vue 文件时,该组件的所有实例将在不刷新页面的情况下被替换。它甚至保持了应用程序和被替换组件的当前状态!当你调整模版或者修改样式时,这极大地提高了开发体验。

    状态保留规则

    • 当编辑一个组件的 <template> 时,这个组件实例将就地重新渲染,并保留当前所有的私有状态。能够做到这一点是因为模板被编译成了新的无副作用的渲染函数。(template实际上被渲染为render函数,应该是无法比较函数之间的异同的,通过比较两个函数返回的v-node树的异同,来判断哪些节点需要销毁,热更新的效果应该和渲染的原理一样;只是生成新的渲染,它本身对传入的参数值没有任何改动,所以不会影响到其他元素的渲染效果,可以做到无副作用。生命周期钩子可能会在执行过程中改变这些变量,所以必须整个组件销毁重建,来触发这些生命周期函数;当传入值prop改变时,组件内部没有变动,不会引起副作用,依然采用构建v-node树进行比较最小替换的方式)
    • 当编辑一个组件的 <script> 时,这个组件实例将就地销毁并重新创建。(应用中其它组件的状态将会被保留) 是因为 <script> 可能包含带有副作用的生命周期钩子,所以将重新渲染替换为重新加载是必须的,这样做可以确保组件行为的一致性。这也意味着,如果你的组件带有全局副作用,则整个页面将会被重新加载。
    • <style> 会通过 vue-style-loader 自行热重载,所以它不会影响应用的状态。style的改变似乎不会改变this.$style指向的对象,不然应该触发组件销毁重建的

    用法

    • 当手动设置你的工程时,热重载会在你启动 webpack-dev-server --hot 服务时自动开启。

    关闭热重载

    • 热重载默认是开启的,除非遇到以下情况

      • webpack 的 target 的值是 node (服务端渲染)
      • webpack 会压缩代码(生产环境?)
      • process.env.NODE_ENV === 'production'
    • 可以设置 hotReload: false 选项来显式地关闭热重载:

    module: {
      rules: [
        {
          test: /\.vue$/,
          loader: 'vue-loader',
          options: {
            hotReload: false // 关闭热重载
          }
        }
      ]
    }
    

    自定义块

    • 在 .vue 文件中,你可以自定义语言块。应用于一个自定义块的 loader 是基于这个块的 lang 特性、块的标签名以及你的 webpack 配置进行匹配的。如果找到了一个自定义块的匹配规则,它将会被处理,否则该自定义块会被默默忽略。如果这个自定义块被所有匹配的 loader 处理之后导出一个函数作为最终结果,则这个 *.vue 文件的组件会作为一个参数被这个函数调用。
    • 使用 resourceQuery 来为一个没有 lang 的自定义块匹配一条规则。例如为了匹配自定义块 <docs>:
    //自定义loader用以处理docs标签
    module.exports = function (source, map) {
        this.callback(
            null,
            `export default function (Component) {    // loader导出的函数,Component指向.vue文件(.vue文件的options好像被实例this继承,没有在其他文档看到,这个对象包含什么?)
            Component.options.__docs = ${
            JSON.stringify(source)
            }
          }`,
            map
        )
    }
    
    // webpack配置
    {
      module: {
        rules: [
          {
            resourceQuery: /blockType=docs/,
            loader: require.resolve('./docs-loader.js')
          }
        ]
      }
    }
    
    // 子组件使用(@/components/HelloWorld.vue)
    <docs>
    This is the documentation for component B.
    </docs>
    
    // 父组件引用
    import HelloWorld from '@/components/HelloWorld.vue'
    
    HelloWorld.__docs    =>    JSON.stringify('This is the documentation for component B.')
    

    CSS 提取

    • 请只在生产环境下使用 CSS 提取,这将便于你在开发环境下进行热重载。(vue-cli中,开发环境css通过js动态写入head中,生产环境则会依据build和check分别打包)

    webpack 4

    npm install -D mini-css-extract-plugin
    
    // webpack.config.js
    var MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    module.exports = {
      // 其它选项...
      module: {
        rules: [
          // ... 忽略其它规则
          {
            test: /\.css$/,
            use: [
              process.env.NODE_ENV !== 'production'
                ? 'vue-style-loader'
                : MiniCssExtractPlugin.loader,
              'css-loader'
            ]
          }
        ]
      },
      plugins: [
        // ... 忽略 vue-loader 插件
        new MiniCssExtractPlugin({
          filename: style.css
        })
      ]
    }
    

    webpack 3

    • 这里应该需要对不同开发环境配置不同的webpack配置
    npm install -D extract-text-webpack-plugin
    
    // webpack.config.js
    var ExtractTextPlugin = require("extract-text-webpack-plugin")
    
    module.exports = {
      // 其它选项...
      module: {
        rules: [
          // ...其它规则忽略
          {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract({
              use: 'css-loader',
              fallback: 'vue-style-loader'
            })
          }
        ]
      },
      plugins: [
        // ...vue-loader 插件忽略
        new ExtractTextPlugin("style.css")
      ]
    }
    

    代码校验

    ESLint

    • 官方的 eslint-plugin-vue 同时支持在 Vue 单文件组件的模板和脚本部分的代码校验。只需要在你的 ESLint 配置文件中使用该插件要导入的配置:
    // .eslintrc.js
    module.exports = {
      extends: [
        "plugin:vue/essential"
      ]
    }
    
    • 可以通过命令行用eslint校验某个.vue文件
    eslint --ext js,vue MyComponent.vue
    
    • 使用 eslint-loader开发过程中每次保存的时候就会自动进行代码校验
    npm install -D eslint eslint-loader
    
    // webpack.config.js
    module.exports = {
      // ... 其它选项
      module: {
        rules: [
          {
            enforce: 'pre',    // 请确保它是作为一个 pre-loader 运用的,loader的种类,影响执行的顺序,执行书序分为:后置(post)、行内(normal)、普通(inline)、前置(pre)
            test: /\.(js|vue)$/,
            loader: 'eslint-loader',
            exclude: /node_modules/
          }
        ]
      }
    }
    

    stylelint

    • 支持在 Vue 单文件组件的样式部分的代码校验。(vue-cli好像默认没装)
    • 命令行校验
    stylelint MyComponent.vue
    
    • 使用插件实现自动校验
    npm install -D stylelint-webpack-plugin
    
    / webpack.config.js
    const StyleLintPlugin = require('stylelint-webpack-plugin');
    module.exports = {
      // ... 其它选项
      plugins: [
        new StyleLintPlugin({
          files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'],
        })
      ]
    }
    
  • 相关阅读:
    主流浏览器的内核私有属性css前缀
    判断一个js对象是否是Array,最准确的方法
    JavaScript的void运算符
    js闭包面试题
    请问何为混合应用 (Hybrid APP) ,与原生 Native 应用相比它的优劣势
    将闭包返回赋值给两个变量,执行这两个闭包变量
    js操作符“+”前后的类型转换
    js基本类型和基本包装类型的区别
    只能输入零和非零开头的数字的正则表达式
    将一个非匿名函数赋值给变量再执行这个非匿名函数会如何
  • 原文地址:https://www.cnblogs.com/qq3279338858/p/10142149.html
Copyright © 2011-2022 走看看