vite如何处理项目中的资源

web开发服务器

实现简易的开发服务器

  1. 初始化项目

    新建文件夹

    vite_dev_server

    初始化工程

    npm init -y

    安装服务框架

    npm i koa

    新建入口文件

    index.js

    新增启动脚本

    {
    "scripts": {
    "dev": "node index.js"
    }
    }

    const Koa = require("koa")

    const app = new Koa()

    // 接收到请求后触发use注册的回调函数
    app.use((ctx) => {
    // ctx: 请求上下文; request: 请求信息; response:响应信息;
    console.log("ctx", ctx.request, ctx.response);
    })

    // 启动服务
    app.listen(5173, () => {
    console.log("vite dev serve liste on 5173");
    })

  1. 新建index.html页面返回给浏览器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> hello! my is node sever. </body> </html>

    const Koa = require("koa")
    const fs = require("fs")
    const path = require("path")

    const app = new Koa()

    // 接收到请求后触发use注册的回调函数
    app.use(async (ctx) => {
    // ctx: 请求上下文; request: 请求信息; response:响应信息;
    // console.log("ctx", ctx.request, ctx.response);

    if (ctx.request.url === "/") {
    const indexContent = await fs.promises.readFile(path.resolve(__dirname, "./index.html")) // 读文件
    ctx.response.body = indexContent // 设置响应体
    ctx.response.set("Content-Type", "text/html") // 设置响应体格式, application/json text/html text/javascript
    }
    })

    // 启动服务
    app.listen(5173, () => {
    console.log("vite dev serve liste on 5173");
    })

  1. 新建main.js, 在index.html中引入, 响应给浏览器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> hello! my is node sever. <script type="module" src="/main.js"></script> </body> </html>

    console.log("main js hihi");

    const Koa = require("koa")
    const fs = require("fs")
    const path = require("path")

    const app = new Koa()

    // 接收到请求后触发use注册的回调函数
    app.use(async (ctx) => {
    // ctx: 请求上下文; request: 请求信息; response:响应信息;
    // console.log("ctx", ctx.request, ctx.response);

    if (ctx.request.url === "/") {
    const indexContent = await fs.promises.readFile(path.resolve(__dirname, "./index.html")) // 读文件
    ctx.response.body = indexContent // 设置响应体
    ctx.response.set("Content-Type", "text/html") // 设置响应体格式, application/json text/html text/javascript
    }

    if (ctx.request.url === "/main.js") {
    const mainContent = await fs.promises.readFile(path.resolve(__dirname, "./main.js")) // 读文件
    ctx.response.body = mainContent // 设置响应体
    ctx.response.set("Content-Type", "text/javascript") // 设置响应体格式, application/json text/html text/javascript
    }
    })

    // 启动服务
    app.listen(5173, () => {
    console.log("vite dev serve liste on 5173");
    })

  1. 新建App.vue, 在main.js中引入,响应给浏览器

开发服务返回给浏览器的vue文件已经是编译后的文件了, 我们也要这样做

复制代码
// 我这里请求失败了, 大概是这个输出有问题
console.log("app vue haha")

import "/App.vue"

console.log("main js hihi");

const Koa = require("koa")
const fs = require("fs")
const path = require("path")

const app = new Koa()

// 接收到请求后触发use注册的回调函数
app.use(async (ctx) => {
  // ctx: 请求上下文;  request: 请求信息;  response:响应信息;
  console.log("ctx", ctx.request, ctx.response);

  if (ctx.request.url === "/") {
    const indexContent = await fs.promises.readFile(path.resolve(__dirname, "./index.html")) // 读文件
    ctx.response.body = indexContent // 设置响应体
    ctx.response.set("Content-Type", "text/html") // 设置响应体格式, application/json text/html text/javascript
  }

  if (ctx.request.url === "/main.js") {
    const mainContent = await fs.promises.readFile(path.resolve(__dirname, "./main.js")) // 读文件
    ctx.response.body = mainContent // 设置响应体
    ctx.response.set("Content-Type", "text/javascript") // 设置响应体格式, application/json text/html text/javascript
  }

  if (ctx.request.url === "/app.vue") {

    const appContent = await fs.promises.readFile(path.resolve(__dirname, "./App.vue")) // 读文件
    // /**
    //  * 如果vue文件, 我们要做处理, 转译为JS返回给前端, 这个过程肯定是非常复杂的, 这里了解一下原理
    //  * 1. 简单理解就是要进行字符串替换: appContent.toString().find("<template>") 如果匹配到了内容, 就要把全部内容替换为JS代码
    //  * 2. 实际过程:  经过AST语法分析 ==> 得到所有元素 ==> 使用 Vue.createElement() 方法 ==> 把得到的元素重新构建成原生的DOM
    //  * 3. 核心就是把vue文件转译为JS文件, 因为浏览器只认识JS文件
    //  */

    ctx.response.body = appContent // 设置响应体
    ctx.response.set("Content-Type", "text/javascript") // 设置响应体格式, application/json text/html text/javascript
  }
})


// 启动服务
app.listen(5173, () => {
  console.log("vite dev serve liste on 5173");
})

处理css

了解Vite怎么处理css

vite天生就支持对css文件的直接处理,

  1. 新建index.css

    html,
    body {
    width: 100%;
    height: 100%;
    background-color: aqua;
    }

  2. 在main.js中引入css

    import './index.css'

  3. 启动项目

  1. 下面是vite处理css的步骤
  • vite在读取到main.js中引用到了index.css
  • 直接去使用fs模块去读取index.css中文件内容
  • 直接创建一个style标签,将index.css中文件内容直接copy进style标签里
  • 将style标签插入到index.html的head中
  • 将该css文件中的内容直接替换为js脚本(方便热更新或者css模块化), 同时设置Content-Type为js, 从而让浏览器以JS脚本的形式来执行该css后置的文件

如何避免样式冲突?

  1. 会什么会冲突:
  • 一个组件最外层的元素类名一般取名: wrapper
  • 一个组件最底层的元素雷明明我们一般取名: footer
  • 你取了footer这个名字,别人因为没有看过你这个组件的源代码,也可能去取名footer这个类名
  • 最终可能会导致样式被覆盖(因为类名重复),这就是我们在协同开发的时候很容易出现的问题
  1. 模拟样式冲突:

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body>
    <script src="./main.js" type="module"></script> </body> </html>

    #div {
    width: 200px;
    height: 200px;
    background-color: red;
    }

    #div {
    width: 200px;
    height: 200px;
    background-color: green;
    }

    import './a.css'
    import './b.css'

  1. 如何解决协作开发中的样式冲突问题:
  • cssmodule就是来解决这个问题的

  • module.css(module是一种约定,表示需要开启css模块化)

  • 他会将你的所有类名进行一定规则的替换(将div替换成div_10b22_1)

  • 同时创建一个映射对象{div:"div_10b22_1"}

  • 将替换过后的内容塞进style标签里然后放入到head标签中(能够读到index.html的文件内容)

  • a.module.css内容进行全部抹除,替换成JS脚本

  • 将创建的映射对象在脚本中进行默认导出

    #div {
    width: 200px;
    height: 200px;
    background-color: red;
    }

    #div {
    width: 200px;
    height: 200px;
    background-color: green;
    }

    import './a.module.css'
    import './b.module.css'

vite处理less或css

  1. 当vite识别到.less结尾的文件后, 先把less语法转译为css语法
  2. 按照处理css的步骤继续处理

vite.config.js中的css配置(module篇)

在vite.config.js中我们通过css属性去控制整个vite对于css的处理行为

  1. localConvention: 修改生成的配置对象的key的展示形式 (驼峰还是中划线形式)
  • camelCase: 驼峰命名
  • camelCaseOnly: 只保留驼峰命名
  • dashes: 中划线命令
  • dashesOnly: 只保留中划线命名(理论上是默认值)(实测结果如下, 不知道咋回事)
  • 默认值: 只保留中划线命名
复制代码
#div {
  width: 200px;
  height: 200px;
  background-color: red;
}

#div-conteainer {
  width: 100px;
}

import css from './a.module.css'
console.log(css);

import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    modules: { // 对css模块化的默认行为进行覆盖
      localsConvention: "dashesOnly"
    }
  }
})
  1. scopeBehaviour: 配置当前的模块化行为是模块化 还是全局化

tocal: 开启模块化css, 拼接哈希值 (默认值)

global: 全局化css (关闭模块化css)

复制代码
import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    modules: { // 对css模块化的默认行为进行覆盖
      localsConvention: "camelCaseOnly"
    }
  }
})
  1. generateScopedName: 生成的类名的规则
  • 可以配置为函数,也可以配置成字符串规则: https://github.com/webpack/loader-utils#interpolatename

    import { defineConfig } from 'vite'

    export default defineConfig({
    css: {
    modules: { // 对css模块化的默认行为进行覆盖,最终丢给postcss覆盖其modules配置
    generateScopedName: "[name][local][hash:5]",
    // generateScopedName: (name, filename, css) => {
    // // name: 代表此刻css文件中的类型
    // // filename: 当前css文件的绝对路径
    // // css: 当前的样式
    // return ${name}_${Math.random().toString(36).substr(3, 8)}
    // },
    }
    }
    })

  1. hashPrefix: 生成的hash会根据你的类名+一些其他的字符串(文件名+ 他内部随机生成一个字符串)去进行生成,如果你想要你生成hash更加的独特一点,你可以配置hashPrefix

    import { defineConfig } from 'vite'

    export default defineConfig({
    css: {
    modules: {
    hashPrefix: "wang"
    }
    }
    })

  2. rglobalModulePaths: 你不想参与到css模块化的路径

    import { defineConfig } from 'vite'

    export default defineConfig({
    css: {
    modules: {
    globalModulePaths: ["./b.module.css"]
    }
    }
    })

vite配置文件中css配置(preprocessorOptions篇)

主要是用来配置css预处理的一些全局参数

复制代码
# 假设没有使用构建工具,我们又想去编译less文件的话

yarn add less; # 内含lessc的编译器

# 你只要安装了node,你就可以使用node index.js
# 你只要安装了less 你就可以使用lessc去编译less文件
  1. math: 处理表达式的范围

    import { defineConfig } from 'vite'

    export default defineConfig({
    css: {
    preprocessorOptions: { // 格式key + config, key代表预处理的名
    less: { // 整个配置对象都会最终给到less的执行参数(全局参数)中去
    math: "always", // 默认只会处理()内的表达式, 配置后处理所有表达式
    },
    sass: {}
    }
    }
    })

    #div {
    padding: 20px / 2; // 全部处理
    margin: (20px / 2); // 默认处理
    }

    #配置后的执行效果等同于
    npm lessc --math="always" index.module.less

  2. globalVars: 定义全局变量

很多工程都是这样使用全局变量

复制代码
@mainColor: red

@import url(./variables.less);

#div {
  padding: 20px / 2; // 全部处理
  margin: (20px / 2); // 默认处理
  background-color: @mainColor;
}

也可以这样定义全局变量, 效果一样

复制代码
import { defineConfig } from 'vite'

export default defineConfig({
  css: {
    preprocessorOptions: { // 格式key + config,  key代表预处理的名
      less: { // 整个配置对象都会最终给到less的执行参数(全局参数)中去
        globalVars: { // 全局变量
          mainColor: "red"
        }
      },
      sass: {}
    }
  }
})

devSourcemap 文件索引

  1. 假设我们的代码被压缩或者被编译过了,这个时候假设程序出错,他将不会产生正确的错误位置信息

  2. 如果设置了sourceMap,他就会有一个索引文件 map, 提示我们正确的代码位置信息

    import { defineConfig } from 'vite'

    export default defineConfig({
    css: {
    devSourcemap: false // 默认false, 开启true
    }
    })

  3. 未开启的效果, 只能定位到style标签, 因为编译后就是把sytle标签插入到HTML中

  1. 开启后的效果, 可以定位到正确的源码文件

postcss

vite天生对postcss有非常良好的支持

  1. postcss 他的工作就是保证css执行起来是万无一失的
  • 我们写的css代码(怎么爽怎么来)--> 交给postcss处理 --->调用less sass等预处理器将扩展语法编译为css语法 ->再将高级css语法进行降级--> 在进行前缀补全 --> 浏览器执行
  • 我们写的is代码(怎么爽怎么来)-->babel -->将ts语法转换js语法 -->做一次语法降级 -->浏览器客户端去执行
  1. css的新提案 (未来css将支持css变量)

    :root {
    --globalColor: lightblue;
    }

    #div {
    width: 200px;
    height: 200px;
    background-color: var(--globalColor);
    }

演示下单独使用postcss

  1. 初始化工程

    npm init -y

  2. 安装依赖

    npm install postcss-cli postcss -D

  3. 新建index.css

    :root {
    --globalColor: red;
    }

    div {
    background-color: var(--globalColor);
    }

  4. 编译css文件

    npx postcss index.css -o result.css

    得到的编译结果, 我们没做任何配置, 原样输出

    :root {
    --globalColor: red;
    }

    div {
    background-color: var(--globalColor);
    }
    /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSIsImZpbGUiOiJyZXN1bHQuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiOnJvb3Qge1xyXG4gIC0tZ2xvYmFsQ29sb3I6IHJlZDtcclxufVxyXG5cclxuZGl2IHtcclxuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1nbG9iYWxDb2xvcik7XHJcbn0iXX0= */

  5. 安装预设的配置插件

    npm install postcss-preset-env -D

  6. 添加配置文件

    const postcssPresetEnv = require("postcss-preset-env")

    //预设环境里面是会包含很多的插件
    // 语法降级-->postcss-low-level
    // 编译插件postcss-compiler
    // ... 省的自己一个一个安装了

    module.export = {
    plugins: [postcssPresetEnv(/* pluginOptions */)]
    }

  7. 重新编译 (做了语法兼容处理)

    :root {
    --globalColor: red;
    }

    div {
    background-color: red;
    background-color: var(--globalColor);
    }

  8. 为什么把postcss称为后处理器?

  • 业内把less/sass称为前处理器, 作用是先一步把扩展的css语法转译为原生css语法
  • 把postcss称为后处理器, 作用是后一步把原生css语法中的高级语法做降级处理
  • 实际上postcss本身就可以集成处理less/sass法语的插件
  • 只是随着生态的发展, 在脚手架中集成less/sass, 再把原生css交给postcss处理, 已经形成共识, 所以postcss处理less/sass语法的插件也就没必要维护了

再vite中配置postcss

  1. 安装预设的配置插件

    npm install postcss-preset-env -D

  2. 配置

    import { defineConfig } from 'vite'
    const postcssPresetEnv = require("postcss-preset-env") // 所以的ES规范最终也会编译为commonJS规范. 因为这里是node环境

    export default defineConfig({
    css: {
    postcss: {
    plugins: [postcssPresetEnv()]
    }
    }
    })

  3. 代码

    :root {
    --globalColor: lightblue;
    }

    #div {
    width: 200px;
    height: 200px;
    background-color: var(--globalColor);

    /* 新语法: 盒子宽度设置为父元素宽度的30%, 但最小不小于100px, 最大不大于200px, /
    /
    postcss会帮我们语法降级, vite内部会维护一个主流浏览器的属性支持表, 根据这个表决定是否降级 */
    width: clamp(100px, 30%, 200px);

    user-select: none;
    }

    #div-conteainer {
    width: 100px;
    }

  1. vite也可以识别 postcss.config.js 配置文件, 优先级低于配置属性

处理静态资源

什么是静态资源 ?

  1. 对于服务端, 除了动态API以外,其它资源都被视作静态资源
  2. vite对静态资源基本上是开箱即用的

vite怎么加载静态资源

复制代码
{
  "name": "张三",
  "age": 18
}

// 学习vite怎么加载静态资源
// import imgUrl from "./assets/images/DE.jpg?url" 
import imgUrl from "./assets/images/DE.jpg?raw"
import json from "./a.json"

const img = document.createElement("img")
img.src = imgUrl
document.body.append(img)

// 在vite中, json文件导入后得到对象, 其他工具会的得到JSON字符串
console.log("json=", json);

// 在url模式下(默认), 拿到图片的绝对路径 /assets/images/DE.jpg
// 在raw模式下, 拿到图片文件的 Buffer (二进制字符串) (也就是原始文件)
console.log("imgUrl=", imgUrl);

import './imageLoader.js'

路径别名的配置

  1. 怎么配置

    import { defineConfig } from 'vite'
    import path from 'path'

    export default defineConfig({
    resolve: {
    alias: {
    "@": path.resolve(__dirname, ""),
    "@assets": path.resolve(__dirname, "./assets")
    }
    }
    })

    import imgUrl from "@assets/images/DE.jpg?url"

  2. 实现原理: 服务端会进行字符串替换, 使用到@符号的地方会被替换为绝对路径

vite对svg资源的处理

  1. 概念
  • svg: scalable vector graphics 可伸缩矢量图形(新的图片格式)
  1. 优势
  • 优点: svg是不会失真, 尺寸小
  • 缺点: 没法很好的去表示层次丰富的图片信息
  • 我们在前端领域里更多的是用svg 去做图标
  1. 使用方式

    import svgIcon from './assets/images/AAVE.svg'
    import svgRwa from './assets/images/AAVE.svg?raw'

    // 1.第一种使用svg的方式
    // const img = document.createElement("img")
    // img.src = svgIcon
    // document.body.appendChild(img)

    // 2.第二种使用方式
    document.body.innerHTML = svgRwa
    const svgEl = document.getElementsByTagName("svg")[0]
    svgEl.onmouseenter = function () {
    this.style.fill = "red"
    }

相关推荐
聆风吟º2 小时前
远程录制新体验:Bililive-go与cpolar的无缝协作
开发语言·后端·golang
豆浆whisky3 小时前
netpoll性能调优:Go网络编程的隐藏利器|Go语言进阶(8)
开发语言·网络·后端·golang·go
蓝天白云下遛狗3 小时前
go环境的安装
开发语言·后端·golang
CAir23 小时前
go协程的前世今生
开发语言·golang·协程
@大迁世界3 小时前
Go 会成为“老生态”的新引擎吗?
开发语言·后端·golang
Absinthe_苦艾酒3 小时前
golang基础语法(六)Map
开发语言·后端·golang
-睡到自然醒~3 小时前
Golang 中的字符串:常见错误和最佳实践
开发语言·后端·golang
予非池物3 小时前
ubuntu安装go
开发语言·后端·golang
四月_h4 小时前
vue2动态实现多Y轴echarts图表,及节点点击事件
前端·javascript·vue.js·echarts