vue工具

  1. 云栖社区>
  2. 博客>
  3. 正文

vue工具

webmirror 2017-09-15 17:00:23 浏览2238
展开阅读全文

生产环境部署

开启生产环境模式

开发时,Vue会提供很多警告来帮你解决常见的错误与陷阱。生产时,这些警告语句却没有用,反而会增加你的载荷量。再次,有些警告检查有小的运行时开销,生产环境模式下是可以避免的

不用打包工具

如果用Webpack或Browserify类似的打包工具时,生产状态会在Vue源码中由process.env.NODE_ENV决定,默认在开发状态。Webpack与Browserify两个打包工具都提供方法来覆盖此变量并使用生产状态,警告语句也会被精简掉。每一个vue-cli模板有预先配置好的打包工具,但了解怎样配置会更好

webpack

使用Webpack的DefinePlugin来指定生产环境,以便在压缩时可以让UglifyJS自动删除代码块内的警告语句。例如配置:

var webpack = require('webpack')
module.exports = {
  // ...
  plugins: [
    // ...
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
}

Browserify

运行打包命令,设置NODE_ENV为"production"。等于告诉vueify避免引入热重载和开发相关代码。使用一个全局envify转换bundle文件。这可以精简掉包含在Vue源码中所有环境变量条件相关代码块内的警告语句。例如:

NODE_ENV=production browserify -g envify -e main.js | uglifyjs -c -m > build.js

Rollup

const replace = require('rollup-plugin-replace')
rollup({
  // ...
  plugins: [
    replace({
      'process.env.NODE_ENV': JSON.stringify( 'production' )
    })
  ]
}).then(...)

预编译模板

当需要处理DOM内或JavaScript内的模板时,“从模板到渲染函数”的编译就会在线上发生。通常情况下这种处理是足够快的,但是如果你的应用对性能很敏感最好还是回避。预编译模板最简单的方式就是使用单文件组件--相关的构建设置会自动把预编译处理好,所以构建好的代码已经包含了编译出来的渲染函数而不是原始的模板字符串。如果使用Webpack并且喜欢分离JavaScript和模板文件,可以使用vue-template-loader,它也可以在构建过程中把模板文件转换成为JavaScript渲染函数。

提取组件的css

当使用单文件组件时,组件内的CSS会以

跟踪运行时错误

如果在组件渲染时出现运行错误,错误将会被传递至全局Vue.config.errorHandler配置函数(如果已设置)。利用这个钩子函数和错误跟踪服务(如Sentry,它为Vue提供官方集成),可能是个不错的主意

单文件组件

介绍

在很多Vue项目中,我们使用Vue.component来定义全局组件,紧接着用new Vue({el: '#container'}) 在每个页面内指定一个容器元素

这种方式在很多中小规模的项目中运作的很好,在这些项目里JavaScript只被用来加强特定的视图。但当在更复杂的项目中,或者你的前端完全由JavaScript驱动的时候,下面这些缺点将变得非常明显:

1.全局定义(Global definitions)强制要求每个component中的命名不得重复

2.字符串模板(String templates)缺乏语法高亮,在HTML有多行的时候,需要用到丑陋的\
3.不支持CSS(No CSS support)意味着当HTML和JavaScript组件化时,CSS明显被遗漏

4.没有构建步骤(No build step)限制只能使用HTML和ES5 JavaScript,而不能使用预处理器,如Pug(formerly Jade)和 Babel

文件扩展名为.vue 的 single-file components(单文件组件)为以上所有问题提供了解决方法,并且还可以使用Webpack或Browserify等构建工具

现在我们获得:完整语法高亮、CommonJS模块、组件化的CSS

正如说过的,可以使用预处理器来构建简洁和功能更丰富的组件,比如Pug,Babel(with ES2015 modules),和Stylus

这些特定的语言只是例子,你可以只是简单地使用Babel,TypeScript,SCSS,PostCSS--或者其他任何能够帮助你提高生产力的预处理器。如果搭配vue-loader使用Webpack,它也是把CSS Modules当作第一公民来对待的

怎么看待关注点分离

一个重要的事情值得注意:关注点分离不等于文件类型分离。在现代UI开发中,我们已经发现相比于把代码库分离成三个大的层次并将其相互交织起来,把它们划分为松散耦合的组件再将其组合起来更合理一些。在一个组件里,其模板、逻辑和样式是内部耦合的,并且把他们搭配在一起实际上使得组件更加内聚且更可维护。即便你不喜欢单文件组件,你仍然可以把JavaScript、CSS分离成独立的文件然后做到热重载和预编译

<!-- my-component.vue -->
<template>
  <div>This will be pre-compiled</div>
</template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>

起步

针对刚接触js模块开发系统的用户

有了.vue组件,我们就进入了高级JavaScript应用领域。如果没有准备好的话,意味着还需要学会使用一些附加的工具:

在花些时日了解这些资源后,建议参考webpack-simple。只要遵循指示,就能很快地运行一个用到.vue组件,ES2015和热重载(hot-reloading)的Vue项目!

这个模板使用Webpack,一个能将多个模块打包成最终应用的模块打包工具。在Webpack中,每个模块被打包到bundle之前都由一个相应的“loader”来转换,Vue也提供vue-loader插件来执行.vue单文件组件的转换。这个webpack-simple模板已经为你准备好了所有的东西

单元测试

配置和工具

任何兼容基于模块的构建系统都可以正常使用,例如可以使用Karma进行自动化测试。它有很多社区版的插件,包括对Webpack和Browserify的支持

简单地断言

在测试的代码结构方面,你不必为了可测试在你的组件中做任何特殊的操作。只要导出原始设置就可以了:

<template>
  <span>{{ message }}</span>
</template>
<script>
  export default {
    data () {
      return {
        message: 'hello!'
      }
    },
    created () {
      this.message = 'bye!'
    }
  }
</script>

当测试的组件时,所要做的就是导入对象和 Vue 然后使用许多常见的断言:

// 导入 Vue.js 和组件,进行测试
import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'
// 这里是一些 Jasmine 2.0 的测试,你也可以使用你喜欢的任何断言库或测试工具。
describe('MyComponent', () => {
  // 检查原始组件选项
  it('has a created hook', () => {
    expect(typeof MyComponent.created).toBe('function')
  })
  // 评估原始组件选项中的函数的结果
  it('sets the correct default data', () => {
    expect(typeof MyComponent.data).toBe('function')
    const defaultData = MyComponent.data()
    expect(defaultData.message).toBe('hello!')
  })
  // 检查 mount 中的组件实例
  it('correctly sets the message when created', () => {
    const vm = new Vue(MyComponent).$mount()
    expect(vm.message).toBe('bye!')
  })
  // 创建一个实例并检查渲染输出
  it('renders the correct message', () => {
    const Ctor = Vue.extend(MyComponent)
    const vm = new Ctor().$mount()
    expect(vm.$el.textContent).toBe('bye!')
  })
})

编写可被测试的组件

很多组件的渲染输出由它的props决定。事实上,如果一个组件的渲染输出完全取决于它的props,那么它会让测试变得简单,就好像断言不同参数的纯函数的返回值。看下面这个例子:

<template>
  <p>{{ msg }}</p>
</template>
<script>
  export default {
    props: ['msg']
  }
</script>

你可以在不同的 props 中,通过 propsData 选项断言它的渲染输出:

import Vue from 'vue'
import MyComponent from './MyComponent.vue'
// 挂载元素并返回已渲染的文本的工具函数
function getRenderedText (Component, propsData) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({ propsData: propsData }).$mount()
  return vm.$el.textContent
}
describe('MyComponent', () => {
  it('renders correctly with different props', () => {
    expect(getRenderedText(MyComponent, {
      msg: 'Hello'
    })).toBe('Hello')
    expect(getRenderedText(MyComponent, {
      msg: 'Bye'
    })).toBe('Bye')
  })
})

断言异步更新

由于Vue进行异步更新DOM的情况,一些依赖DOM更新结果的断言必须在Vue.nextTick回调中进行:

// 在状态更新后检查生成的 HTML
it('updates the rendered message when vm.message updates', done => {
  const vm = new Vue(MyComponent).$mount()
  vm.message = 'foo'
  // 在状态改变后和断言 DOM 更新前等待一刻
  Vue.nextTick(() => {
    expect(vm.$el.textContent).toBe('foo')
    done()
  })
})

我们计划做一个通用的测试工具集,让不同策略的渲染输出(例如忽略子组件的基本渲染)和断言变得更简单

TypeScript支持

从2.2.0起针对TS+Webpack 2用户的重要改动

在Vue2.2里,我们引入了新机制,把dist文件都作为ES模块发布。这在webpack 2中属于默认行为。遗憾的是,这个改动会引入一个会破坏兼容性的意外改动。在TypeScript+webpack 2里,import Vue = require('vue')会返回一个综合的ES模块对象,而不是Vue对象本身。我们计划在未来把所有官方类型声明都改成ES-风格的导出方式

发布为NPM包的官方声明文件

静态类型系统能帮助你有效防止潜在的运行时错误,而且随着应用日渐丰满会更加显著。这就是为什么Vue不仅仅为Vue core提供针对TypeScript的官方类型声明,还为Vue Router和Vuex也提供了相应的声明文件。而且,我们已经把他们发布于NPM,最新版本的TypeScript也知道该如何自己从NPM包里解析类型声明。这意味着只要你成功地通过NPM安装了,就不再需要任何额外的工具辅助,即可在Vue中使用TypeScript

推荐配置

{ // tsconfig.json
  "compilerOptions": {
    // ... 已省略其它选项
    "allowSyntheticDefaultImports": true,
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ]
  }
}

请注意:allowSyntheticDefaultImports选项允许你使用下列语法:

import Vue from 'vue'

而不是这种:

import Vue = require('vue') // 注:老语法

我们更为推荐前者(ES模块语法),因为他跟原生的ES用法更为一致,而且在未来,我们计划把官方声明全部搬迁到ES风格的导出方式。另外,如果你是搭配webpack 2使用TypeScript,那么以下配置也很推荐:

{
  "compilerOptions": {
    // ... 已省略其他配置
    "module": "es2015",
    "moduleResolution": "node"
  }
}

这句选项告诉TypeScript不要处理ES模块引入语句(译注:import .. from ..)。这样webpack 2就可以充分利用其基于ES模块的tree-shaking

使用Vue的类型声明

Vue的类型声明导出了很多有效的类型声明。比如,标记一个导出的组件选项对象(e.g. 在 .vue 文件中):

import Vue, { ComponentOptions }  from 'vue'
// 声明该组件的类型
interface MyComponent extends Vue {
  message: string
  onClick (): void
}
export default {
  template: '<button @click="onClick">Click!</button>',
  data: function () {
    return {
      message: 'Hello!'
    }
  },
  methods: {
    onClick: function () {
      // TypeScript 知道 `this` 是类型为 MyComponent 的对象
      // 因此 `this.message` 会是一个 string
      window.alert(this.message)
    }
  }
// 我们需要显式地标注导出选项对象为 MyComponent 类型
} as ComponentOptions<MyComponent>

不幸的是,这里也有一些局限性:

1.TypeScript不能推断出Vue API里的所有类型。比如,他们不知道我们data 函数中返回的message属性会被添加到MyComponent实例中。这意味着如果我们给message赋值一个数字或者布尔值,linter和编译器并不能抛出一个“该值应该是字符串”的错误。

2.因为第一条的局限, 如上的类型注释可能会很罗嗦。TypeScript不能正确推导message的类型,是唯一迫使我们手动声明它是string的原因。好消息是,vue-class-component能解决以上的两个问题。这是一个官方的姐妹库,它能允许你把组件声明为一个原生的JavaScript类,外加一个@Component的修饰符。为了举例说明,我们把上面的例子重写一下吧:

import Vue from 'vue'
import Component from 'vue-class-component'
@Component({ // @Component 修饰符注明了此类为一个 Vue 组件  
  template: '<button @click="onClick">Click!</button>' // 所有的组件选项都可以放在这里
})
export default class MyComponent extends Vue {  
  message: string = 'Hello!' // 初始数据可以直接声明为实例的属性  
  onClick (): void { // 组件方法也可以直接声明为实例的方法
    window.alert(this.message)
  }
}

有了这种备选语法,我们的组件定义不仅更加短小,而且TypeScript也能在无需显式接口声明的情况下,正确推断message和onClick的类型。这个策略甚至能让你处理计算属性(computed),生命周期钩子以及render函数的类型

生命vue插件补充的类型

插件可以增加Vue的全局/实例属性和组件选项。在这些情况下,在TypeScript中制作插件需要类型声明。庆幸的是,TypeScript有一个特性来补充现有的类型,叫做模块补充(module augmentation)

例如,声明一个string类型的实例属性$myProperty:

import Vue from 'vue' // 1. 确保在声明补充的类型之前导入 'vue'
declare module 'vue/types/vue' { // 2. 定制一个文件设置你想要补充的类型;在types/vue.d.ts里Vue有构造函数类型
  interface Vue { // 3. 声明为 Vue 补充的东西 
    $myProperty: string
  }
}

在项目中包含了上述作为声明文件的代码后(像 my-property.d.ts),就可以在Vue实例上使用 $myProperty 了

var vm = new Vue()
console.log(vm.$myProperty) // 将会顺利编译通过

你也可以声明额外的属性和组件选项:

import Vue from 'vue'
declare module 'vue/types/vue' {  
  namespace Vue { // 可以使用 `namespace` 替代 `interface`来声明全局属性
    const $myGlobal: string
  }
}
declare module 'vue/types/options' { // ComponentOptions 声明于 types/options.d.ts 之中
  interface ComponentOptions<V extends Vue> {
    myOption?: string
  }
}

上述的声明允许下面的代码顺利编译通过:

console.log(Vue.$myGlobal) // 全局属性
var vm = new Vue({ // 额外的组件选项
  myOption: 'Hello'
})

网友评论

登录后评论
0/500
评论
webmirror
+ 关注