基于 Vite 从 0 到 1 启动一个 Vue2 项目

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

本篇文章就是教学如何基于 vite01 启动一个 Vue 项目,下面是这个项目运行效果

IMG

传统启动

如果你是刚开始接触 HTML/CSS/JavaScript 三件套开始接触的前端,那么你可能比较熟悉或者比较能接受的引入 Vue 的方式可能是使用 CDN 的方式,大概如下(下面这个是我要介绍的例子)

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body>
  <div id="app">
    <div>
      {{ "count:" + count }}
      <button @click="handleClick">click + 1</button>
    </div>
  </div>
</body>
<script>
  new Vue({
    data() {
      return {
        count: 0,
      }
    },
    methods: {
      handleClick() {
        this.count++;
      },
    }
  }).$mount('#app');
</script>

但如果你继续深入学习的话或者看过一些学习视频,他们可能会推荐你去使用 Webpack 或者 Vite 等一些成熟的工具链去开发项目,而前面我有一篇文章介绍过基于 Webpack 从 0 到 1 启动一个 Vue 项目,那么如何通过 Vite 去运行一个项目呢? 接下来就教你们一步步简单运行一个 Vue 项目

Vite 启动

先找个位置并在终端(或者命令行)初始化一个项目

npm init

初始化后会有一些选项,可以直接回车全部忽略,也可以根据自己意向填写

IMG

选择完成之后

IMG

这个时候系统会创建一个 package.json 文件

IMG

接下来要做的就是安装 Vue

# 文章使用的 Vue2 运行
npm install vue@2.7.10

然后你的 package.json 会有多出一个 dependencies 属性,如下

{
  "dependencies": {
    "vue": "^2.7.10"
  }
}

所以上面的例子需要改成如下写法

// <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
import Vue from "vue"

但这种写法在 HTML 文件需要使用 module 加持,而且现在的 Vue 的位置在 node_modules,不能再从 HTML 中直接导入,所以需要将上面例子中的 JS 代码脱离,命名为 main.js

import Vue from "vue";

new Vue({
  data() {
    return {
      count: 0,
    }
  },
  methods: {
    handleClick() {
      this.count++;
    },
  }
}).$mount('#app');

html 部分命名为 index.html

<body>
  <div id="app">
    <div>
      {{ "count:" + count }}
      <button @click="handleClick">click + 1</button>
    </div>
  </div>
</body>
<script src="./main.js"></script>

此时的文件结构

├── node_modules
├── main.js
├── index.html
├── package-lock.json
└── package.json

如果你有过 HTML 部署的经验或者你的电脑上的 VS Code 恰好有 Live Server 这个软件,你会发现这个文件结构已经能够运行

但是效果和预期不一样,会是下面这样

IMG

此时控制台会有一个错误

Uncaught SyntaxError: Cannot use import statement outside a module (at main.js:1:1)

这个错误的意思是无法在模块外部使用 import,虽然但是,我没能理解它这个的意思

IMG

不过这个错误的原因是我们在引入的 main.js 中使用了 ES Module 语法/规范

import Vue from "vue";

那么如何能够解决这个报错呢?这里可以普及一下 esm 的理念,现在浏览器已经支持直接使用 ES Module,这意味着使用 ES Module 规范的模块可以直接在浏览器中使用,其实这也是 Vite 这类框架的出现的基础,直接使用模块而不再是打包成一个文件引用

而解决这个问题的具体的操作如下

完成以下操作,需要下载 Live Server 插件

  1. 第一步,在 index.html 的引入脚本中开启 type="module",如下
<body>
  <div id="app">
    <div>
      {{ "count:" + count }}
      <button @click="handleClick">click + 1</button>
    </div>
  </div>
</body>
<script type="module" src="./main.js"></script>
  1. 第二步,开启 package.json"type": "module"
{
  // ...
  "type": "module",
  // ....
}
  1. 第三步,最骚的来了,根据这个对不同构建版本的解释 – Vue.js 文档找到对应的文件 vue.esm.broswer.js(可以直接在浏览器使用,而且既有编译时又有运行时),然后拖出来和 index.html 在同一文件夹下,修改 main.js 的导入方式

PS: 有编译时的 Vue.js 才可以正确解析 {{ "count:" + count }}

import Vue from "./vue.esm.browser.js"

// ...

此时的文件结构

├── node_modules
├── main.js
├── index.html
├── vue.esm.browser.js
├── package-lock.json
└── package.json

再次刷新运行

IMG

解析成功

你可能会觉得主动去 node_modules 里拖出一个文件也太秀了,有没有一种工具可以直接找到并运行在浏览器里呢?没错,vite 就是干这件事的

Vite

npm install vite --save-dev

新增 script

{
  // ..
  "scripts": {
    "dev": "vite",
  },
  // ...
}

修改 main.js

import Vue from "vue";

新增 vite.config.js 文件

import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
  // root 默认值是 process.cwd(), 即当前工作文件夹
  // 所以例子中的 index.html 无需任何修改
  // 同时 index.html 中引用的 .js 需要在同一个 root 目录下
  root: process.cwd(),
  server: {
    port: 5173, // 默认端口是 5173
  },
  plugins: [vue()],
});

注意:由于 Vite 配置有一些默认值,所以我将一些关键的属性重写并做了注释

运行 npm run dev,结果如下

IMG

同样解析成功

与 Webpack 比较

比较一下 Webpack 启动 Vue2 项目和 Vite 启动 Vue2 项目的终端/命令行对比图

Vite

IMG

Webpack

IMG

通过上面的图片可以看出来,Vite 好像其实就是只开了 5173 的服务,而 Webpack 却的实打实的 code generated(打包),同时这就是这两个开发工具为什么在速度上会有差距,回到 Vite 文档的两张图,你会更清楚两者的工作原理

Vite

IMG

Webpack

IMG

在看一下刚才的例子是不是真的请求过我们的 Vue 模块

IMG

添加 .vue 支持

有朋友可能会问了,你这个味道不对呀,我平时开发都是用的 .vue 后缀的文件开发呀,我要用单文件组件(Single File Components (SFCs))开发!

对于现在的前端工程化来说,不可能全部 html 代码都写在同一个文件里,正确的处理方式是编写 SFC 然后通过 JS 模块化统一导入到 html

IMG

对于 JS 的模块化当然是只能导入 .js 文件,但是为了便于平时的开发,Vue 框架提供了 .vue 文件(SFC)的选择,然后通过编译转成 .js 文件

而在 Vite 中提供这一支持的是

由于本篇文章采用的是 vue@2.7.10,因此需要导入 @vitejs/vite-plugin-vue2

npm install @vitejs/plugin-vue2 --save-dev

修改 vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue2";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
});

迁移 index.html 模板内容和 main.js 部分 JavascriptApp.vue

<!-- index.html -->
<body>
  <div id="app"></div>
</body>
<script type="module" src="./main.js"></script>
// main.js
import Vue from "vue";
import App from "./App.vue";

new Vue({
  render: (h) => h(App),
}).$mount("#app");
<!-- App.vue -->
<template>
  <div>
    {{ "count:" + count }}
    <button @click="handleClick">click + 1</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    handleClick() {
      this.count++;
    },
  },
};
</script>

再次运行 npm run dev,解析成功

IMG

从上面文章其实有一些问题并没有详细讲解,读者看完可以思考一下

  1. 为什么通过 import Vue from 'vue' 能够直接找到 node_modules 中的对应文件
    1. import Vue from 'vue' 是怎么判断是 CommonJS 还是 ES Module
    2. 设置 <script type="module" ... />package.json 的属性 "type": "module" 之后,为什么 import Vue from 'vue' 默认导出的是仅运行时的 Vue,即 vue.runtime.esm.js
  2. 基于 ES Module 规范导入模块/库/包,那么面对一些老的库,不支持 ES Module 时,Vite 会怎么处理?

本篇文章例子的 githubpandoralink/vue2-start-with-vite

参考资料

  1. 为什么选 Vite – Vite 官方文档
  2. 对不同构建版本的解释 – Vue.js 文档
© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容