对vueloader的研究

vue-loaderwebpack的加载器,允许您以称为单文件组件(SFC)的格式创作Vue组件

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style>
.example {
  color: red;
}
</style>

有许多很酷的功能提供vue-loader

  • 允许对Vue组件的每个部分使用其他webpack加载器,例如Sass for <style>和Pug for <template>;
  • 允许.vue文件中的自定义块可以应用自定义加载器链;
  • 处理在模块依赖项中引用的静态资产,<style><template>使用webpack加载器处理它们;
  • 模拟每个组件的范围CSS;
  • 在开发过程中保持国家的热再加载。

简而言之,webpack的组合vue-loader为您提供了一个现代,灵活且极其强大的前端工作流程,用于创作Vue.js应用程序。

Vue的CLI

如果您对手动设置webpack不感兴趣,建议使用Vue CLI构建项目Vue CLI创建的项目预先配置了大多数开箱即用的常见开发需求。

如果Vue CLI的内置配置不符合您的需要,请遵循本指南,或者您更愿意从头开始创建自己的webpack配置。

手动配置

Vue Loader的配置与其他加载器略有不同。除了适用vue-loader于任何带扩展名的文件的规则外,请.vue务必将Vue Loader的插件添加到webpack配置中:

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      // ... other rules
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // make sure to include the plugin!
    new VueLoaderPlugin()
  ]
}

这个插件是必需的!它负责克隆您定义的任何其他规则并将它们应用于.vue文件中的相应语言块例如,如果您有规则匹配/\.js$/,则它将应用于文件中的<script>.vue

一个更完整的webpack配置示例如下所示:

// webpack.config.js
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      // this will apply to both plain `.js` files
      // AND `<script>` blocks in `.vue` files
      {
        test: /\.js$/,
        loader: 'babel-loader'
      },
      // this will apply to both plain `.css` files
      // AND `<style>` blocks in `.vue` files
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // make sure to include the plugin for the magic
    new VueLoaderPlugin()
  ]
}

资产URL处理

当Vue Loader <template>在SFC中编译块时,它还会将遇到的任何资产URL转换为webpack模块请求

例如,以下模板代码段:

<img src="../image.png">

将编译成:

createElement('img', {
  attrs: {
    src: require('../image.png') // this is now a module request
  }
})

默认情况下,将转换以下标记/属性组合,并可使用transformAssetUrls选项进行配置

{
  video: ['src', 'poster'],
  source: 'src',
  img: 'src',
  image: 'xlink:href'
}

此外,如果您已配置使用css-loader,则<style>CSS中的资产URL也将以类似的方式处理。

转换规则

资产URL转换遵循以下规则:

  • 如果URL是绝对路径(例如/images/foo.png),则它将按原样保留。

  • 如果URL以#开头.,则将其解释为相对模块请求,并根据文件系统上的文件夹结构进行解析。

  • 如果URL以...开头~,则将其解释为模块请求。这意味着您甚至可以引用节点模块内的资产:

    <img src="~some-npm-package/foo.png">
    
  • 如果URL以@,它也被解释为模块请求。如果您的webpack配置具有别名@这非常有用,默认情况下,该别名指向/src由其创建的任何项目vue-cli

因为扩展.png不是JavaScript模块,所以您需要配置webpack以使用file-loaderurl-loader来正确处理它们。使用Vue CLI创建的项目已预先配置。

为什么

资产URL转换的好处是:

  1. file-loader允许您指定复制和放置资产文件的位置,以及如何使用版本哈希命名它以获得更好的缓存。此外,这也意味着您只需将图像放在*.vue文件旁边,并根据文件夹结构使用相对路径,而不必担心部署URL通过适当的配置,webpack将自动将文件路径重写为捆绑输出中的正确URL。

  2. url-loader允许您有条件地将文件内联为base-64数据URL(如果它们小于给定阈值)。这可以减少普通文件的HTTP请求数量。如果文件大于阈值,则会自动回退到file-loader

使用预处理器

在webpack中,所有预处理器都需要应用相应的加载器。vue-loader允许您使用其他webpack加载器来处理Vue组件的一部分。它将根据lang语言块属性和webpack配置中的规则自动推断要使用的正确加载器

SASS

例如,要<style>使用SASS / SCSS 编译我们的标记:

npm install -D sass-loader node-sass

在您的webpack配置中:

module.exports = {
  module: {
    rules: [
      // ... other rules omitted

      // this will apply to both plain `.scss` files
      // AND `<style lang="scss">` blocks in `.vue` files
      {
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  },
  // plugin omitted
}

现在除了能够之外import 'style.scss',我们还可以在Vue组件中使用SCSS:

<style lang="scss">
/* write SCSS here */
</style>

块中的任何内容都将由webpack处理,就像它在*.scss文件中一样。

上海社会科学院VS SCSS

请注意,默认情况下sass-loader处理非基于缩进的scss语法。要使用基于缩进的sass语法,您需要将选项传递给加载器:

// 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: {
        // you can also read from a file, e.g. `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'
  ]
}

手写笔

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

PostCSS

小费

Vue Loader v15默认不再适用PostCSS变换。您需要使用PostCSS postcss-loader

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

PostCSS的配置可以通过postcss.config.jspostcss-loader选项完成有关详细信息,请参阅postcss-loader docs

postcss-loader 也可以与上述其他预处理器结合使用。

巴贝尔

npm install -D babel-core babel-loader
// webpack.config.js -> module.rules
{
  test: /\.js?$/,
  loader: 'babel-loader'
}

Babel的配置可以通过.babelrcbabel-loader选项完成

不包括node_modules

exclude: /node_modules/对于babel-loader适用于.js文件的JS转换规则(例如通常是常见的由于v15的推断变化,如果在内部导入Vue SFC node_modules,其<script>部分也将被排除在转换之外。

为了确保将JS转换应用于Vue SFC node_modules,您需要使用exclude函数将它们列入白名单:

{
  test: /\.js$/,
  loader: 'babel-loader',
  exclude: file => (
    /node_modules/.test(file) &&
    !/\.vue\.js/.test(file)
  )
}

打字稿

npm install -D typescript ts-loader
// webpack.config.js
module.exports = {
  resolve: {
    // Add `.ts` as a resolvable extension.
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      // ... other rules omitted
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: { appendTsSuffixTo: [/\.vue$/] }
      }
    ]
  },
  // ... plugin omitted
}

TypeScipt的配置可以通过tsconfig.json另请参阅ts-loader的文档

帕格

处理模板有点不同,因为大多数webpack模板加载器如pug-loader返回模板函数而不是编译的HTML字符串。pug-loader我们需要使用一个返回原始HTML字符串的加载器,而不是使用,例如pug-plain-loader

npm install -D pug pug-plain-loader
// webpack.config.js -> module.rules
{
  test: /\.pug$/,
  loader: 'pug-plain-loader'
}

然后你可以写:

<template lang="pug">
div
  h1 Hello world!
</template>

如果您还打算使用它.pug在JavaScript中将文件作为HTML字符串导入,则需要raw-loader在预处理加载器之后进行链接但请注意,添加raw-loader会破坏Vue组件中的使用,因此您需要有两个规则,其中一个使用a定位Vue文件resourceQuery,另一个(回退)定位JavaScript导入:

// webpack.config.js -> module.rules
{
  test: /\.pug$/,
  oneOf: [
    // this applies to `<template lang="pug">` in Vue components
    {
      resourceQuery: /^\?vue/,
      use: ['pug-plain-loader']
    },
    // this applies to pug imports inside JavaScript
    {
      use: ['raw-loader', 'pug-plain-loader']
    }
  ]
}

作用域CSS

<style>标签具有该scoped属性时,其CSS将仅应用于当前组件的元素。这类似于Shadow DOM中的样式封装。它有一些警告,但不需要任何polyfill。通过使用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>

混合本地和全局样式

您可以在同一组件中包含范围和非范围样式:

<style>
/* global styles */
</style>

<style scoped>
/* local styles */
</style>

子组件根元素

使用时scoped,父组件的样式不会泄漏到子组件中。但是,子组件的根节点将受父级作用域CSS和子级作用域CSS的影响。这是设计的,以便父级可以设置子根元素的样式以进行布局。

深度选择器

如果您希望scoped样式中的选择器“深入”,即影响子组件,则可以使用>>>组合器:

<style scoped>
.a >>> .b { /* ... */ }
</style>

以上将编译成:

.a[data-v-f3f3eg9] .b { /* ... */ }

某些预处理器(如Sass)可能无法>>>正确解析在这些情况下,您可以使用/deep/组合器 - 它是别名,>>>并且完全相同。

动态生成的内容

创建的DOM内容v-html不受范围样式的影响,但您仍然可以使用深度选择器设置它们的样式。

也记住

  • 范围样式不会消除类的需要由于浏览器呈现各种CSS选择器的方式,p { color: red }在作用域时(即与属性选择器结合时)会慢很多倍。如果您使用类或ID,例如in .example { color: red },那么您几乎可以消除性能损失。这是一个游乐场,您可以自己测试差异。

  • 在递归组件中注意后代选择器!对于带有选择器的CSS规则.a .b,如果匹配的元素.a包含递归子组件,则.b该子组件中的所有组件都将与规则匹配。

 

CSS模块

CSS模块是用于模块化和组合CSS的流行系统。vue-loader提供与CSS模块的一流集成,作为模拟范围CSS的替代方案。

用法

首先,必须通过传递modules: truecss-loader

// webpack.config.js
{
  module: {
    rules: [
      // ... other rules omitted
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          {
            loader: 'css-loader',
            options: {
              // enable CSS Modules
              modules: true,
              // customize generated class names
              localIdentName: '[local]_[hash:base64:8]'
            }
          }
        ]
      }
    ]
  }
}

然后,将module属性添加到您的<style>

<style module>
.red {
  color: red;
}
.bold {
  font-weight: bold;
}
</style>

module属性指示Vue Loader将CSS模块locals对象作为具有名称的计算属性注入组件$style然后,您可以在模板中使用动态类绑定:

<template>
  <p :class="$style.red">
    This should be red
  </p>
</template>

由于它是一个计算属性,它也可以使用以下对象/数组语法:class

<template>
  <div>
    <p :class="{ [$style.red]: isRed }">
      Am I red?
    </p>
    <p :class="[$style.red, $style.bold]">
      Red and bold
    </p>
  </div>
</template>

您还可以从JavaScript访问它:

<script>
export default {
  created () {
    console.log(this.$style.red)
    // -> "red_1VyoJ-uZ"
    // an identifier generated based on filename and className.
  }
}
</script>

有关模式详细信息(如全局异常组合),请参阅CSS模块规范

选择使用

如果您只想在某些Vue组件中使用CSS模块,则可以使用oneOf规则并检查module字符串resourceQuery

// webpack.config.js -> module.rules
{
  test: /\.css$/,
  oneOf: [
    // this matches `<style module>`
    {
      resourceQuery: /module/,
      use: [
        'vue-style-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true,
            localIdentName: '[local]_[hash:base64:5]'
          }
        }
      ]
    },
    // this matches plain `<style>` or `<style scoped>`
    {
      use: [
        'vue-style-loader',
        'css-loader'
      ]
    }
  ]
}

与预处理器一起使用

CSS模块可以与其他预处理器一起使用:

// webpack.config.js -> module.rules
{
  test: /\.scss$/,
  use: [
    'vue-style-loader',
    {
      loader: 'css-loader',
      options: { modules: true }
    },
    'sass-loader'
  ]
}

自定义进样名称

您可以<style>在单个*.vue组件中包含多个标记为避免注入样式相互覆盖,可以通过为module属性赋值来自定义注入的计算属性的名称

<style module="a">
  /* identifiers injected as a */
</style>

<style module="b">
  /* identifiers injected as b */
</style>

热刷新

“Hot Reload”不仅仅是在编辑文件时重新加载页面。启用热重新加载后,在编辑*.vue文件时,将交换该组件的所有实例,而无需重新加载页面它甚至可以保留您的应用程序和这些交换组件的当前状态!当您调整组件的模板或样式时,这可以显着改善开发体验。

热重装

州保存规则

  • 编辑<template>组件时,已编辑组件的实例将重新呈现,保留所有当前的私有状态。这是可能的,因为模板被编译成新的渲染函数,不会产生副作用。

  • 编辑<script>组件一部分时,将销毁并重新创建已编辑组件的实例。(保留应用程序中其他组件的状态)这是因为<script>可能包含可能产生副作用的生命周期钩子,因此需要“重新加载”而不是重新呈现以确保一致的行为。这也意味着您需要注意全局副作用,例如组件生命周期钩子中的计时器。如果您的组件产生全局副作用,有时您可能需要执行整页重新加载。

  • <style>热重载依次运行vue-style-loader,因此不会影响应用程序状态。

用法

搭建项目时vue-cli,Hot Reload可以开箱即用。

手动设置项目时,在使用项目服务时会自动启用热重新加载webpack-dev-server --hot

高级用户可能想要查看内部使用的vue-hot-reload-apivue-loader

禁用热重新加载

除以下情况外,始终启用热重新加载:

  • webpack targetnode(SSR)
  • webpack缩小了代码
  • process.env.NODE_ENV === 'production'

您可以使用hotReload: false选项明确禁用热重新加载:

module: {
  rules: [
    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        hotReload: false // disables Hot Reload
      }
    }
  ]
}

功能组件

*.vue文件中定义为单文件组件的功能组件也接收适当的模板编译,Scoped CSS和热重载支持。

要表示应编译为功能组件functional的模板,请将该属性添加到模板块。这也允许省略块中functional选项<script>

模板中的表达式在功能渲染上下文中进行评估这意味着需要像props.xxx在模板中一样访问props 

<template functional>
  <div>{{ props.foo }}</div>
</template>

如果需要访问全局定义的属性Vue.prototype,可以在parent以下位置访问它们

<template functional>
  <div>{{ parent.$someProperty }}</div>
</template>

自定义块

您可以在*.vue文件中定义自定义语言块应用于自定义块的加载器将根据块的lang属性,块的标记名称以及webpack配置中的规则进行匹配。

如果lang指定属性,则自定义块将作为文件lang与其扩展名匹配

您还可以使用resourceQuery匹配自定义块的规则lang例如,要匹配<foo>自定义块:

{
  module: {
    rules: [
      {
        resourceQuery: /blockType=foo/,
        loader: 'loader-to-use'
      }
    ]
  }
}

如果为自定义块找到匹配规则,则会对其进行处理; 否则将自动忽略自定义块。

此外,如果自定义块在所有匹配的加载器处理后将函数导出为最终结果,则将使用*.vue文件的组件作为参数调用该函数

例子

下面是将<docs>自定义块注入组件的示例,以便在运行时可用。

为了注入自定义块内容,我们将编写一个自定义加载器:

module.exports = function (source, map) {
  this.callback(
    null,
    `export default function (Component) {
      Component.options.__docs = ${
        JSON.stringify(source)
      }
    }`,
    map
  )
}

现在我们将配置webpack以使用我们的自定义加载器来<docs>定制块。

// wepback.config.js
module.exports = {
  module: {
    rules: [
      {
        resourceQuery: /blockType=docs/,
        loader: require.resolve('./docs-loader.js')
      }
    ]
  }
}

我们现在能够<docs>在运行时访问块的导入组件的内容。

<!-- ComponentB.vue -->
<template>
  <div>Hello</div>
</template>

<docs>
This is the documentation for component B.
</docs>
<!-- ComponentA.vue -->
<template>
  <div>
    <ComponentB/>
    <p>{{ docs }}</p>
  </div>
</template>

<script>
import ComponentB from './ComponentB.vue';

export default {
  components: { ComponentB },
  data () {
    return {
      docs: ComponentB.__docs
    }
  }
}
</script>

CSS提取

小费

仅对生产应用CSS提取,以便在开发期间获得CSS热重新加载。

的WebPack 4

npm install -D mini-css-extract-plugin
// webpack.config.js
var MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  // other options...
  module: {
    rules: [
      // ... other rules omitted
      {
        test: /\.css$/,
        use: [
          process.env.NODE_ENV !== 'production'
            ? 'vue-style-loader'
            : MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // ... Vue Loader plugin omitted
    new MiniCssExtractPlugin({
      filename: 'style.css'
    })
  ]
}

另请参阅mini-css-extract-plugin文档

的WebPack 3

npm install -D extract-text-webpack-plugin
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")

module.exports = {
  // other options...
  module: {
    rules: [
      // ... other rules omitted
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          use: 'css-loader',
          fallback: 'vue-style-loader'
        })
      }
    ]
  },
  plugins: [
    // ... Vue Loader plugin omitted
    new ExtractTextPlugin("style.css")
  ]
}

Linting

#ESLint

The official eslint-plugin-vue supports linting both the template and script parts of Vue single file components.

Make sure to use the plugin's included config in your ESLint config:

// .eslintrc.js
module.exports = {
  extends: [
    "plugin:vue/essential"
  ]
}

Then from the command line:

eslint --ext js,vue MyComponent.vue

Another option is using eslint-loader so that your *.vue files are automatically linted on save during development:

npm install -D eslint eslint-loader

Make sure it's applied as a pre-loader:

// webpack.config.js
module.exports = {
  // ... other options
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/
      }
    ]
  }
}

#stylelint

stylelint supports linting style parts of Vue single file components.

Make sure that your stylelint config is right.

Then from the command line:

stylelint MyComponent.vue

Another option is using stylelint-webpack-plugin:

npm install -D stylelint-webpack-plugin

Make sure it's applied as a plugin:

// webpack.config.js
const StyleLintPlugin = require('stylelint-webpack-plugin');
module.exports = {
  // ... other options
  plugins: [
    new StyleLintPlugin({
      files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'],
    })
  ]
}

测试




















































































 

posted @ 2018-08-30 19:19  又回到了起点  阅读(2658)  评论(0编辑  收藏  举报