Vue 学习(七、Webpack 和 Vue 的基础搭建)


一、Vue 模板编译版和运行时版


1. Vue 提供的各个版本


Vue 的 NPM 包中有多个版本供我们实际使用时选择,路径为 node_modules\vue\dist,内容如下:
Vue提供过的各个版本
虽然看上去版本非常多,但其实可以按照文件名规则对其进行归类,分类规则如下:

环境符合 CommonJS 规范符合 ES6 规范符合 CommonJS + ES6 规范
模板编译版本前缀为:vue.common前缀为:vue.esmvue.js 和 vue.min.js
运行时版本前缀为:vue.runtime.common前缀为:vue.runtime.esmvue.runtime.js 和 vue.runtime.js

Webpack 打包时,默认使用的是 符合 CommonJS 规范的运行时版本, 详见路径:node_modules\vue\package.json
Vue默认版本

2. 从模板解析到渲染的大致流程

从模板解析到渲染的大致流程
介绍几个概念后再理解图中的流程就简单多了:

  • AST:抽象语法树(Abstract Syntax Tree),简单来说就是个树形结构的对象,HTML 模板字符串最终会转成该结构对象
  • Render 函数:其函数体是通过递归 AST 树状对象动态生成的,该函数执行后会构建出 Virtual DOM
  • Virtual DOM:又是一个树状对象,因为其出现的目的是减少 DOM 操作,所以又叫它虚拟 DOM

如果想详细的学习整个渲染原理,还是得阅读源码和源码分析的文章,推荐个学习地址 - Vue 源码系列 - Vue 中文社区

3. 模板编译版和运行时版的区别


前面我们已经知道了,从模板解析到渲染的大致流程,而那正是模板编译版的流程,运行时版本的流程和它是有区
别的,流程如下图:

运行时版本流程
可以看出来,运行时版本相较模板编译版本,少了两个步骤:

  • 把 HTML 模板 转成 AST 对象
  • 递归 AST 对象,动态生成 Render 函数体

这样有一个优点,就是运行时版本没有 AST 相关代码,所以代码体积更小,适合生产环境,但同时又有一个问题,
图中可以看出运行时版本是直接执行 Render 函数的,而 Render 函数的函数体,应该是基于 AST 动态生成,现在没
有 AST 了,就代表 Render 函数没有函数体,那应该怎么办 ?

解决方式很简单,既然没有函数体,那么我们就手动为 Render 函数指定一个函数体,在 Vue 对象的 options 中有
一个可选函数 render,它会被 Vue 回调,这就是我们指定 Render 函数体的地方


1) options.render 函数在被调用时,会被传入一个参数 createElement,所以可以将函数体声明为:

new Vue({
  el:'#app',
  render: function(createElement){
    return null
  }
})
// 或简写为箭头函数
new Vue({
  el:'#app',
  render: createElement => {
    return null
  }
})

2) 参数 createElement 也是一个函数,其用来在虚拟 DOM 上创建元素

createElement 的语法:createElement(element, properties, children),应用举例:


// 场景 1:对应 html 为,
// <div id='container' style='border:1px solid black; width:100px; height:100px'> 这是内容 </div>
new Vue({
  el: '#app',
  render: (createElement) => {
    return createElement(
      'div', {
        id: 'container',
        style: 'border:1px solid black; width:100px; height:100px'
      },
      ['这是内容'])
  }
})
// 场景 2:对应 html 为,
// <div id='container' style='border:1px solid black; width:100px; height:100px'>
//   <span id="content">这是内容</span>
// </div>
new Vue({
  el: '#app',
  render: (createElement) => {
    return createElement('div', {
      id: 'container',
      style: 'border:1px solid black; width:100px; height:100px'
    }, [createElement('span', {id: 'content'}, ['这是内容'])])
  }
})

所以当选择使用运行时版本的场景,一定要注意,不要使用 template 属性,而要手动指定 render 函数体

二、Webpack 中使用 Vue


通过往期的文章,已经有了 npm 和 webpack 的基础,现在我将一步步记录它们搭配 vue 的细节

1. 搭配 Vue 最原始的方式


1) 初始化项目,并安装必要依赖

创建项目文件夹,并在根目录通过 CMD 依次执行如下命令:

# 初始化为 npm 管理的项目
npm init -y
# 安装 webpack 相关依赖
npm i webpack webpack-cli -D
# 安装 vue
npm i vue --save

2) 创建入口 JS 文件

创建 项目/src/index.js 文件(默认入口),并在文件内导入 Vue 模块和使用 Vue 对象,内容如下:

import Vue from 'vue'
new Vue({
  el: '#app',
  data: {
    message: '通过 webpack 引入的 vue 模块,已被正确使用!!!'
  }
})

3) 创建 HTML 文件,并预先引入出口文件

创建 项目/index.html 文件,并预先引入出口文件( 此处我们使用的是默认出口,路径为 项目/dist/main.js),最后在
HTML 文件内使用 Vue 语法,目的是后期验证 Vue 语法否能被正确解析

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>vue-study</title>
  <style>
    p {
      width: 800px;
      height: 18px;
      line-height: 18px;
      border: 1px solid black;
      background-color: gray;
    }
  </style>
</head>
<body>
  <div id="app">
    <p>这是 Vue 语法转换后的内容:{{message}}</p>
  </div>
  <script src="./dist/main.js"></script>
</body>
</html>

4) 修改 npm 的配置文件

修改 package.json 文件, 添加自定义脚本 "build":"webpack", 之后就可以通过 npm run build 来运行 webpack

{
  "name": "vue-study",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1"
  },
  "dependencies": {
    "vue": "^2.6.14"
  }
}

5) 添加 webpack 的配置文件

将配置文件创建在 webpack 的默认查找路径中 项目/webpack.config.js,Vue 默认使用的是运行时版本,本例要使用
模板编译版本,所以要在这个文件中指定。当然如果使用运行时版本就不需要这个文件了,但不要忘了定义 render 函数

module.exports = {
  mode: 'development',
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
}

6) 通过 webpack 打包,并确认目录结构

项目根目录中通过 CMD 运行 npm run build 命令,进行 webpack 打包,打包后的项目结构如下:
请添加图片描述

7) 运行 HTML ,验证 Vue 语法是否被正确解析
验证vue语法是否被正确解析

2. 使用 template 属性代替挂载元素中的内容


我们前面学习 Vue 组件时知道,Vue 对象本身也可以视为一个组件,既根组件,所以它的 options 中,也包含
template 属性,而根组件的 template 的内容很特殊,它会在运行时替换 el 属性挂载的元素的原始内容

现将前例做如下修改:

1) 修改 HTML

删除 index.html#app 元素的内容,修改后如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>vue-study</title>
</head>
<body>
  <div id="app"></div>
  <script src="./dist/main.js"></script>
</body>
</html>

2) 修改入口 JS 文件

修改 index.js,将原 #app 中的内容,写在 template 属性中,修改后如下:

import Vue from 'vue'
new Vue({
  el: '#app',
  template: '<p style="width: 800px;' +
                      'height: 18px;' +
                      'line-height: 18px;' +
                      'border: 1px solid black;' +
                      'background-color: gray;">这是 Vue 语法转换后的内容: {{message}}</p>',
  data: {
    message: '通过 webpack 引入的 vue 模块,已被正确使用!!!'
  }
})

3) 打包编译,查看运行结果
验证vue语法是否被正确解析
这种方式可以将 HTML 文件变得非常整洁干净,文件中只有基本的 HTML 骨架代码、引入出口文件的语句和待挂载
的空元素三类内容,可能很好奇,让 HTML 变得这么简洁有什么意义吗,其实这是为了迎合单页面应用的思想,单页
面应用的具体概念会在后续的路由篇章介绍


三、Vue-Loader 和 .Vue 文件


前例中我们将布局内容都放到了 Vue 对象的 template 属性中来保持 HTML 文件的简洁,但这会带来一个问题

前面学 Vue 组件化 时知道, 布局代码写在 template 属性中,不易读也不易维护,所以我们当时使用了模板抽离来提
升可维护性,模板抽离依托于 HTML 文件,而我们现在为了保证 HTML 文件的简洁,所以不能对其修改,那该怎么做呢?


1. 创建 .Vue 格式文件


为了解决这个问题,Vue 提供了新的文件格式来实现模板抽离,既 .Vue 格式,其文件语法很简单,分为三部分:

<template>
 <!-- 第一部分:此处用来写 HTML 代码 -->
</template>

<script>
  // 第二部分:此处用来写 JS 代码
</script>

<style>
  /* 第三部分:此处用来写 CSS 代码 */
</style>

现在对之前的例子做修改:

1) 创建 .vue 文件

创建新的目录和文件,例中目录为 src/vue/App.vue,内容如下:

<template>
  <div>
    <p>这是 Vue 语法转换后的内容:{{ message }}</p>
  </div>
</template>

<script>
// 导出组件对象
export default {
  data() {
    return {
      message: "通过 webpack 引入的 vue 模块,已被正确使用!!!",
    }
  }
}
</script>

<style scoped>
p {
  width: 800px;
  height: 18px;
  line-height: 18px;
  border: 1px solid black;
  background-color: gray;
}
</style>

这种文件格式,将代码清晰的分成三部分,非常利于阅读和维护,其中 <style scoped> 中的 scoped 代表样式的作用
域,加上后,只有当前组件受影响,如果不写,当多个组件拼成一个页面时,可能会影响其他组建的样式


2) 修改 index.js 文件

以模块的方式,导入.vue 文件中导出的 JS 对象,并以组件的方式注册到 Vue 对象中,实现如下:

import Vue from 'vue'
import App from './vue/App.vue'

new Vue({
  el: '#app',
  template: '<App></App>',
  components: {
    App
  }
})

3) 确认当前项目结构
vue文件项目结构

2. 使用 vue-loader 预编译 .vue 格式文件


我们在 index.js 文件中,使用 ES6 语法导入了 Vue 模块(既 .vue 格式文件),但 ES6 语法并不认识 .vue 格式文
件,所以是不能直接使用 webpack 命令进行编译打包的,这个时候我们就要借助加载器,对入口文件中的特殊语法进行转译


1) 安装 vue-loader 加载器

# 安装 vue-loader 相关加载器,样式相关加载器也必须安装
npm i vue-loader vue-template-compiler css-loader style-loader -D

2) 修改 webpack 配置文件

修改 webpack.config.js 配置文件,添加 vue-loader 和 样式相关加载器的配置信息

const VUE_LOADER_PLUGIN = require('vue-loader/lib/plugin')
module.exports = {
  mode: 'development',
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  module: {
    rules: [{
        test: /\.vue$/,
        use: ['vue-loader']
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [
    new VUE_LOADER_PLUGIN()
  ]
}

3) 编译打包,验证结果

运行 npm run build 打包,并运行 index.html 查看结果
请添加图片描述

四、结语


webpack + .vue 格式文件 + vue-loader 的方式,可以让我们未来实现单页面应用时,代码更清晰易读、易维护

我们想完成一个产品级的 Vue 项目搭建,需要手动创建项目结构,手动配置需要的 webpack 加载器和插件,这样
做不仅很繁琐,而且配出来的也不一定是最优选择,之后我们要学习能帮我们自动搭建产品级 Vue 项目的工具 Vue-CLI

它会自动帮我们创建出大部分项目都在使用的项目结构及更严谨的 webpack 配置文件

不同版本可能配置会有差异,下面列出本文使用的包版本:

{
  "devDependencies": {
    "css-loader": "^6.5.1",
    "style-loader": "^3.3.1",
    "vue-loader": "^15.9.8",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1"
  },
  "dependencies": {
    "vue": "^2.6.14"
  }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值