一、Vue 开发模式

目前我们使用 vue 的过程都是在 html 文件中,通过 template 编写自己的模板、脚本逻辑、样式等

但是随着项目越来越复杂,我们会采用组件化的方式来进行开发:这就意味着每个组件都会有自己的模板、脚本逻辑、样式等

当然我们依然可以把它们抽离到单独的 js、css 文件中,但是它们还是会分离开来;也包括我们的 script 是在一个全局的作用域下,很容易出现命名冲突的问题

并且我们的代码为了适配一些浏览器,必须使用 ES5 的语法

在我们编写代码完成之后,依然需要通过工具对代码进行构建、代码

所以在真实开发中,我们可以通过一个后缀名为 .vue 的 single-file components (单文件组件) 来解决,并且可以使用 webpack 或者 vite 或者 rollup 等构建工具来对其进行处理

单文件特点

代码的高亮

ES6、CommonJS 的模块化能力

组件作用域的 CSS

可以使用预处理器来构建更加丰富的组件,比如 TypeScript、Babel、Less、Sass 等

如何支持 SFC

方式一:使用 Vue CLI 来创建项目,项目会默认帮助我们配置好所有的配置选项,可以在其中直接使用.vue 文件

方式二:自己使用 webpack 或 rollup 或 vite 这类打包工具,对其进行打包处理

最终,无论是后期我们做项目,还是在公司进行开发,通常都会采用 Vue CLI 的方式来完成

二、webpack

随着前端的快速发展,目前前端的开发已经变的越来越复杂了:

  • 比如开发过程中我们需要通过模块化的方式来开发
  • 比如也会使用一些高级的特性来加快我们的开发效率或者安全性,比如通过 ES6+、TypeScript 开发脚本逻辑, 通过 sass、less 等方式来编写 css 样式代码
  • 比如开发过程中,我们还希望实时的监听文件的变化来并且反映到浏览器上,提高开发的效率
  • 比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化
  • 等等….

对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中根本就没有面临这些问题:

  • 这是因为目前前端开发我们通常都会直接使用三大框架来开发:Vue、React、Angular
  • 但是事实上,这三大框架的创建过程我们都是借助于脚手架(CLI)的
  • Vue-CLI、create-react-app、Angular-CLI 都是基于 webpack 来帮助我们支持模块化、less、 TypeScript、打包优化等的

webpack 是什么

webpack is a static module bundler for modern JavaScript applications.

webpack 是一个静态的模块化打包工具,为现代的 JavaScript 应用程序;

对上面的解释进行拆解:

  • 打包 bundler:webpack 可以将帮助我们进行打包,所以它是一个打包工具
  • 静态的 static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器)
  • 模块化 module:webpack 默认支持各种模块化开发,ES Module、CommonJS、AMD 等
  • 现代的 modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了 webpack 的出现和发展

webpack 安装

webpack 的安装目前分为两个:webpack、webpack-cli

那么它们是什么关系呢?

  • 执行 webpack 命令,会执行 node_modules 下的.bin 目录下的 webpack
  • webpack 在执行时是依赖 webpack-cli 的,如果没有安装就会报错
  • 而 webpack-cli 中代码执行时,才是真正利用 webpack 进行编译和打包的过程
  • 所以在安装 webpack 时,我们需要同时安装 webpack-cli(第三方的脚手架事实上是没有使用 webpack-cli 的,而是类似于自己的 vue-service-cli 的东西)
1
2
npm install webpack webpack-cli –g # 全局安装
npm install webpack webpack-cli –D # 局部安装

webpack 默认打包

我们可以通过 webpack 进行打包,之后运行打包之后的代码

  • 在目录下直接执行 webpack 命令
  • 生成一个 dist 文件夹,里面存放一个 main.js 的文件,就是我们打包之后的文件
  • 这个文件中的代码被压缩和丑化了
  • 暂时不关心他是如何做到的,后续讲 webpack 实现模块化原理时会再次讲到
  • 另外发现代码中依然存在 ES6 的语法,比如箭头函数、const 等,这是因为默认情况下 webpack 并不清楚我 们打包后的文件是否需要转成 ES5 之前的语法,后续需要通过 babel 来进行转换和设置

我们发现是可以正常进行打包的,但是有一个问题

  • webpack 是如何确定我们的入口的呢? 事实上,当我们运行 webpack 时,webpack 会查找当前目录下的 src/index.js 作为入口
  • 所以,如果当前项目中没有存在 src/index.js 文件,那么会报错

当然,我们也可以通过配置来指定入口和出口 Webpack 的默认打包

  • npx webpack –entry ./src/main.js –output-path ./build

局部 webpack

前面我们直接执行 webpack 命令使用的是全局的 webpack,

如果项目中使用的 webpack 版本和全局的不一样,就会产生冲突。

如果希望使用局部的可以按照下面的步骤来操作。

第一步:创建 package.json 文件,用于管理项目的信息、库依赖等

  • npm init

第二步:安装局部的 webpack

  • npm install webpack webpack-cli -D

第三步:使用局部的 webpack

  • npx webpack

第四步:在 package.json 中创建 scripts 脚本,执行脚本打包即可创建局部的

1
2
3
4
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build":"webpack"
},
  • npm run build

对 vue 代码的打包

npm i vue@next

1
2
3
4
import { createApp } from 'vue'; // Vue代码 const app = createApp({ template: "
<h2>我是vue</h2>
", data() { return { title: "Hello World", message: "哈哈哈" } } }); // const
app = createApp(App); app.mount("#app");

因为使用的 vue 打包后的版本不对

vue 打包后不同版本解析

vue(.runtime).global(.prod).js:

  • 通过浏览器中的 script 标签直接引用
  • 之前通过 CDN 引入和下载的 Vue 版本就是这个版本
  • 会暴露一个全局的 Vue 来使用

vue(.runtime).esm-browser(.prod).js:

  • 用于通过原生 ES 模块导入使用 (在浏览器中通过<script type=module>来使用)

vue(.runtime).esm-bundler.js:

  • 用于 webpack,rollup 和 parcel 等构建工具
  • 构建工具中默认是 vue.runtime.esm-bundler.js
  • 如果我们需要解析模板 template,那么需要手动指定 vue.esm-bundler.js

vue.cjs(.prod).js:

  • 服务器端渲染使用
  • 通过 require()在 Node.js 中使用

runtime 指的是运行时,不包含对 template 的编译

prod 是指生产环境,压缩后的代码

运行时+编译器 vs 仅运行时

在 Vue 的开发过程中我们有三种方式来编写 DOM 元素:

  • 方式一:template 模板的方式(之前经常使用的方式)
  • 方式二:render 函数的方式,使用 h 函数来编写渲染的内容
  • 方式三:通过.vue 文件中的 template 来编写模板

它们的模板分别是如何处理的呢?

  • 方式二中的 h 函数可以直接返回一个虚拟节点,也就是 Vnode 节点
  • 方式一和方式三的 template 都需要有特定的代码来对其进行解析:
  • 方式三.vue 文件中的 template 可以通过在 vue-loader 对其进行编译和处理
  • 方式一种的 template 我们必须要通过源码中一部分代码来进行编译

所以,Vue 在让我们选择版本的时候分为

运行时+编译器

仅运行时

  • 运行时+编译器包含了对 template 模板的编译代码,更加完整,但是也更大一些
  • 仅运行时没有包含对 template 版本的编译代码,相对更小一些
1
2
// 更改代码 指定版本即可正常显示
import { createApp } from 'vue/dist/vue.esm-bundler';

VSCode 对 SFC 文件的支持

插件一:Vetur,从 Vue2 开发就一直在使用的 VSCode 支持 Vue 的插件

插件二:Volar,官方推荐的插件(后续会基于 Volar 开发官方的 VSCode 插件)

编写 App.vue 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<h2>我是Vue渲染出来的</h2>
<h2>{{ title }}</h2>
<hello-world></hello-world>
</template>

<script>
import HelloWorld from "./HelloWorld.vue";

export default {
components: {
HelloWorld,
},
data() {
return {
title: "Hello World",
message: "哈哈哈",
};
},
methods: {},
};
</script>

<style scoped>
h2 {
color: red;
}
</style>

导入

1
2
import { createApp } from 'vue/dist/vue.esm-bundler'; import App from
'./vue/App.vue'; const app = createApp(App); app.mount("#app");

App.vue 的打包过程

对代码打包会报错:我们需要合适的 Loader 来处理文件

  • npm install vue-loader -D

在 webpack 的模板规则中进行配置:

1
2
3
4
{
test: /\.vue$/,
loader: "vue-loader"
}

打包依然会报错,这是因为我们必须添加@vue/compiler-sfc 来对 template 进行解析

  • npm install @vue/compiler-sfc -D

另外我们需要配置对应的 Vue 插件

1
2
const { VueLoaderPlugin } = require('vue-loader/dist/index');
new VueLoaderPlugin()

重新打包即可支持 App.vue 的写法