什么是Vite?

  • 法语:轻量化,快速
  • 基于VUE3 非 打包开发服务器,请注意,它是个开发服务器哇!!
  • 快速开发,按需编译,不再等待整个应用编译完成
  • 基于原生模块系统ESModule实现
  • 说白了,就是一个node.js服务器,帮你运行起来代码,让你可以调试
  • 它和我们部署的webserver不同的是,里面内置了websoket,当监听到代码改变 通过websoket更新代码,实现热更新

实现原理

  • 使用export import 方式导入导出模块,同时实现按需加载
  • 高度依赖module script 特性

下面开始搞事情吧~~

  • 兼容性注意
  • Vite 需要 Node.js 版本 >= 12.0.0。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。

新建一个文件夹,执行命令,构建一个 Vite + Vue 项目

# npm 6.x
npm create vite@latest my-vue-app --template vue # npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue

进入项目,执行

 cd my-vue-app
npm install
npm run dev

恭喜哇,项目跑起来啦~

  • 复制地址用浏览器访问

打开项目看一下我们的目录

看个厉害的e

是不是很好奇,为什么会可以直接加载.vue文件呢???接下来我们就开始探索一下吧

  • 新建一个文件夹 vite,然后进去执行下面命令
npm init -y
  • 然后生成了一个package.json文件



  • 安装依赖 koa 用来实现node服务器,它帮我们封装了node-http哦
npm install koa

  • 接下来我们看一下,当我们执行 npm run dev 的时候,实际是执行了下面的命令,如果我们想要实现这个命令,我们又该怎么做呢?

新建命令执行入口 vite\bin\www.js

配置package.json

"bin":"./bin/www.js",

配置执行环境(这个是必须写的哇)

#! /usr/bin/env node

// 这个就是我们的入口文件啦~~

console.log('xiaojin love code!')

配置环境映射?怎么说,这个就是把这个环境临时搞到全局,让cmd也可以用

npm link

当然,还有更好玩的东西

  • 我把命令改了一下,好玩多了
{
"name": "vite",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin":{
"xiaojin": "./bin/www.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.13.4"
}
}

新建一个文件编写服务代码,先跑一把玩一下 vite\src\server.js

const Koa = require('koa')
const { Static } = require('vue')
function createServer() {
let app = new Koa()
// 实现静态服务功能,访问我们的服务器可以返回对应的文件koa-Static
return app
}
createServer().listen(8088,()=>{
console.log('xiaojin server is start at 8088')
})

使用nodemon来监控代码变化,然后来自动重新执行,我们要执行下面的命令,其实我之前用过另一个叫做 surpervisor,也是可以的

npm i nodemon

在外层新建一个配置文件,监控这个目录的代码变化 nodemon.json

{
"watch":["vite"],
"exec":"xiaojin"
}



记得配置这个

重新执行nodemon命令试一把,记得,是在外层哦

nodemon

下个步骤,等我今天晚上熬夜写完继续补充

来啦~~

接下来我们来实现,通过服务访问静态资源

  • 就直接用我们外层的那个文件 index.html,添加几句测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
测试代码哦~
测试一下我们的静态资源读取情况~
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
  • 安装 koa-static
PS C:\jin_files\code\testDemo\vite-demo\my-vue-app> cd vite
PS C:\jin_files\code\testDemo\vite-demo\my-vue-app\vite> npm install koa-static

  • 新增vite\src\serverPluginServerStatic.js,编写静态插件调用的逻辑代码
const static = require('koa-static')

function staticPlugin({app,root}) {
app.use(static(root)) // 这个root指的是根目录哦~~当我访问我的服务localhost:8088的时候,它会去找根目录下面的index.html
}
module.exports = staticPlugin
  • 在server.js里,编辑代码,搞一下插件,先来实现静态服务功能
const Koa = require('koa')
const staticPlugin = require('./serverPluginServerStatic')
function createServer() {
let app = new Koa()
// 实现静态服务功能,访问我们的服务器可以返回对应的文件koa-Static
const context = { // 创建一个上下文,给不同插件共享功能
app,
root:process.cwd() // 这个目录就在vite-vue
}
const resolvePlugin = [staticPlugin]
resolvePlugin.forEach(plugin => plugin(context))
return app
}
createServer().listen(8088,()=>{
console.log('xiaojin server is start at 8088')
console.log('修改代码跑一把')
})
  • 关键代码标记给大家:



  • 然后,去浏览器里输入http://localhost:8088/,看一下效果吧~~

  • 很成功哇,我们的服务调用了静态资源,运行起来啦

配置一下,访问public目录试一把

  • 根路径下,创建测试文件public\test.txt
I am xiaojin ,I love code~

  • 进入vite\src\serverPluginServerStatic.js添加代码
const static = require('koa-static')
const path = require('path')
function staticPlugin({app,root}) {
app.use(static(root)) // 这个root指的是根目录哦~~当我访问我的服务localhost:8088的时候,它会去找根目录下面的index.html
app.use(static(path.resolve(root,'public')))
}
module.exports = staticPlugin

  • 访问http://localhost:8088/test.txt,试一把~
  • 成功啦~~

打开F12看一下

  • 啊哦~ 报错了
  • Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".



怎么才能正常显示我们的资源不报错呢???就是说,如何让这句话 import { createApp } from 'vue' 正常执行?

冷静分析

  • es6模块会自动发送请求,查找相应文件
  • vite所做的事情就是: 根据你需要的文件,进行改写
  • 我们发请求,请求了main.js文件
  • 我们可以在后端将main.js里的内容进行改写操作,将所有不带./ ../ / 的全部加一个/@modules去寻找相应资源,不就不会报错了吗??

添加模块重写代码逻辑,重写我们的请求路径哇~~

  • 新建文件 vite\src\serverPluginModuleRewrite.js

function reWritePlugin({app,root}) {
app.use(async (ctx, next) =>{
// todu:
await next() // 先走静态服务,因为默认会先执行 静态服务中间件,将结果放到ctx.body
// 需要将流转换为字符串,而且我们只需要处理其中JS的引用问题
console.log('reWritePlugin:')
if(ctx.body && ctx.response.is('js')){
console.log(ctx.body)
console.log('ctx.body已打印完毕')
} })
}
module.exports = reWritePlugin
  • 添加插件引用代码到vite\src\server.js
const reWritePlugin = require('./serverPluginModuleRewrite')
function createServer() {
...
const resolvePlugin = [
reWritePlugin, // 重写请求路径插件 ,为什么这么写这个顺序呢,原因解释放到插件里吧~~
staticPlugin, // 静态服务插件
]
...
}

  • 访问http://localhost:8088/,然后查看你的命令行

好了,我要睡觉了,明天继续写

睡觉中......

继续开工啦~~

接下来开始读取文件流,

  • 解决 vite\src\serverPluginModuleRewrite.js 中需要将流转换为字符串,而且我们只需要处理其中JS的引用问题
  • 创建vite\src\utils.js
const {Readable} = require('stream')
async function readBody(stream) {
if(stream instanceof Readable) {
return new Promise((resolve,reject)=>{
let res = ''
stream.on('data',function(chunk){
res += chunk
})
stream.on('end',function() {
resolve(res)
})
})
}else{
return stream
}
}
exports.readBody = readBody
  • 修改代码vite\src\serverPluginModuleRewrite.js
const { readBody } = require("./utils")

function reWritePlugin({app,root}) {
app.use(async (ctx, next) =>{
// todu:
await next() // 先走静态服务,因为默认会先执行 静态服务中间件,将结果放到ctx.body
// 需要将流转换为字符串,而且我们只需要处理其中JS的引用问题
console.log('reWritePlugin:')
if(ctx.body && ctx.response.is('js')){
// console.log(ctx.body) // 这个打出来是main.js的文件流
let res = await readBody(ctx.body)
console.log(res)
console.log('ctx.body已打印完毕')
} })
}
module.exports = reWritePlugin



访问http://localhost:8088/,试一把

打印完成啦~~开心(),接下来我们开始解析并改写文件内容(就是把VUE文件解析处理为 @/modules)

  • 我们需要安装插件,处理字符串
  • es-module-lexer 可以解析所有的import语法
  • magic-string 处理字符串,把字符串变成对象类型,引用类型
  • 外层执行:

npm install es-module-lexer magic-string

  • 给 vite\src\serverPluginModuleRewrite.js 添加解析代码
const {parse} = require('es-module-lexer')
function reWriteImports(source) {
let imports = parse(source)
console.log(imports)
}

  • 刷新一下页面,看打印结果
修改代码跑一把
reWritePlugin:
reWritePlugin:
[
[
{ n: 'vue', s: 27, e: 30, ss: 0, se: 31, d: -1, a: -1 },
{ n: './App.vue', s: 49, e: 58, ss: 32, se: 59, d: -1, a: -1 }
],
[],
false
]
reWriteRes已打印完毕
  • 解释一下这个是什么哦

开始编写重写文件逻辑啦

const { readBody } = require("./utils")
const { parse } = require('es-module-lexer')
const MagicString = require('magic-string')
function reWriteImports(source) {
let imports = parse(source)[0]
// console.log(imports)
// 路径处理逻辑开始咯
let ms = new MagicString(source)
if (imports.length > 0) {
imports.forEach(_ => {
let { s, e, n } = _
let id = n
console.log('old id :', id)
if (/^[^\/\.]/.test(id)) {
id = `/@modules/${id}`
console.log('new id :', id)
ms.overwrite(s, e, id)
}
})
}
return ms.toString()
} function reWritePlugin({ app, root }) {
app.use(async (ctx, next) => {
// todu:
await next() // 先走静态服务,因为默认会先执行 静态服务中间件,将结果放到ctx.body
// 需要将流转换为字符串,而且我们只需要处理其中JS的引用问题
console.log('reWritePlugin:')
if (ctx.body && ctx.response.is('js')) {
// console.log(ctx.body) // 这个打出来是main.js的文件流
let res = await readBody(ctx.body)
const reWriteRes = reWriteImports(res)
ctx.body = reWriteRes
// console.log(reWriteRes)
console.log('reWriteRes已打印完毕')
} })
}
module.exports = reWritePlugin
  • 重点改了这里哦



  • 给大家看一下打印出来的内容

old id : vue
new id : /@modules/vue
old id : ./App.vue

跑一把试一下,main.js已经被改写成功了呢~~~~

继续睡觉啦,明天接着写~~

从0到1手把手实现vite的更多相关文章

  1. 从0开始,手把手教你用Vue开发一个答题App01之项目创建及答题设置页面开发

    项目演示 项目演示 项目源码 项目源码 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把 ...

  2. 从0开始,手把手教你用Vue开发一个答题App

    项目演示 项目演示 项目源码 项目源码 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把 ...

  3. 从0开始,手把手教你使用React开发答题App

    项目演示地址 项目演示地址 项目源码 项目源码 其他版本教程 Vue版本 小程序版本 项目代码结构 前言 React 框架的优雅不言而喻,组件化的编程思想使得React框架开发的项目代码简洁,易懂,但 ...

  4. ActionMQ5.8.0 JMS实例 手把手详细图解

    出自:http://blog.csdn.net/tongjie008/article/details/40687087 ActionMQ 是开源的JMS实现 1.下载ActiveMQ 去官方网站下载: ...

  5. 从0开始,手把手教你开发并部署上线一个知识测验微信小程序

    上线项目演示 微信搜索[放马来答]或扫以下二维码体验: 项目源码 项目源码 其他版本 Vue答题App实战教程 Hello小程序 1.注册微信小程序 点击立即注册,选择微信小程序,按照要求填写信息 2 ...

  6. vite 动态 import 引入打包报错解决方案

    关注公众号: 微信搜索 前端工具人 ; 收货更多的干货 原文链接: 自己掘金文章 https://juejin.cn/post/6951557699079569422/ 关注公众号: 微信搜索 前端工 ...

  7. 快速新建并配置一个eslint+prettier+husky+commitlint+vue3+vite+ts+pnpm的项目

    前置准备 一台电脑 vscode pnpm vscode插件:ESLint v2.2.6及以上 vscode插件:Prettier - Code formatter v9.5.0及以上 vscode插 ...

  8. React Native教程

    React Native 中文网  http://reactnative.cn/ 相关资料======================= React-Native学习指南 https://github ...

  9. Vue3发布半年我不学,摸鱼爽歪歪,哎~就是玩儿

    是从 Vue 2 开始学基础还是直接学 Vue 3 ?尤雨溪给出的答案是:"直接学 Vue 3 就行了,基础概念是一模一样的." 以上内容源引自最新一期的<程序员>期刊 ...

  10. ZAM 3D 制作简单的3D字幕 流程(二)

    原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...

随机推荐

  1. Python基础阶段总结:ATM项目实战

    目录 ATM逻辑描述 三层框架简介 1.第一层(src.py) 2.第二层(interface文件夹下内容) 3.第三层(db_hanlder) 启动函数 用户注册功能 用户登录 common中的小功 ...

  2. JS 学习笔记 (六) 函数式编程

    1.函数闭包 1.1 概述 JavaScript采用词法作用域,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的. 为了实现这种词法作用域,JavaScript函数对 ...

  3. Go语言核心36讲33

    我们在前几次讲的互斥锁.条件变量和原子操作都是最基本重要的同步工具.在Go语言中,除了通道之外,它们也算是最为常用的并发安全工具了. 说到通道,不知道你想过没有,之前在一些场合下里,我们使用通道的方式 ...

  4. Android Studio打开时报错if you already hava 64-bit JDK installed,define a JAVA_HOME

    出现这个问题不知道改了什么导致的,卸载了重新安装也是不行. 以及到高级设置中进行配置jdk也是无效, 解决方法为需要在路径 C:\Users\你自己的用户名\AppData\Roaming\Googl ...

  5. Devexpress控件searchLookUpEdit获得选中行的其他列数据

    使用searchLookUpEdit控件获得选中行的其他列的数据.比如有一列代码列和一列描述.那么我们选中一行后想获得选中的代码和描述.可以在searchLookUpEdit1_EditValueCh ...

  6. python(牛客)试题解析3 - 困难

    导航 一.找到已经最大承重的背包内如何放入最大价值的物品的最优解 二.查找一个字符串中包含另外一个字符串(可打乱顺序)的次数三.计算正整数数组从头走到最后一个成员所需的最小步骤四.计算字符串非严格递增 ...

  7. 关于Linux mint更换中文字体后全局楷体修改办法

    问题描述 linux mint 更新中文字体后,全局都变成了楷体,浏览器里面,终端里(英文字体可以在终端设置里面修改),这里指的是中文字体,而英文字体可以在 linux mint 设置 - 选择字体 ...

  8. HSSFSheet XSSFWorkbook SXSSF Java读取Excel数据

    HSSF是POI工程对Excel 97(-2007)文件操作的纯Java实现 XSSF是POI工程对Excel 2007 OOXML (.xlsx)文件操作的纯Java实现 SXSSF通过一个滑动窗口 ...

  9. 【消息队列面试】15-17:高性能和高吞吐、pull和push、各种MQ的区别

    十五.kafka高性能.高吞吐的原因 1.应用 日志收集(高频率.数据量大) 2.如何保证 (1)磁盘的顺序读写-pagecache关联 rabbitmq基于内存读写,而kafka基于磁盘读写,但却拥 ...

  10. 猿人学web爬虫攻防大战

    这里有1.2.3.4.12.13.15题 1.第一题 import execjs import requests def get_response(): js_code = ""& ...