vite学习

vite学习笔记

目录

在这里插入图片描述

Vite 通过在一开始将应用中的模块区分为 依赖源码 两类,改进了开发服务器启动时间。

  • 依赖 大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。

    Vite 将会使用 esbuild 预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

  • 源码 通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。

    Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

    在这里插入图片描述

    vite做了什么

    模块按需加载(webpack首次加载需要从入口文件开始根据依赖图加载全部js,耗时长;vite基于浏览器,首次加载时只按需加载需要显示在当前页面的模块,

    依赖预构建(vite借助esbuild进行了预构建,对项目依赖进行扫描,将得到的依赖结果缓存起来,并存放在node_module/.vite/deps目录下。(一个文件)

    热更新HMR热更新指的是自动对页面上更改的模块进行替换,以达到刷新页面数据的效果,这个效果甚至是无感的。)**

    ts解析

    css解析

    代码压缩

    vite配置文件!(重要)

    vite.config.js

    export default{
    	optimizeDeps:{
    		exclude:['']//项目中不需要依赖与构建的依赖
    	}
    }
    

    一、语法提示

    一、

    import {defineConfig} from 'vite'
    export default defineConfig({
    	optimizeDeps:{
    		exclude:['']//项目中不需要依赖与构建的依赖
    	}
    })
    

    二、

    
    /** @type import('vite').defineConfig */
    const config = {
    	optimizeDeps:{
    		exclude:['']//项目中不需要依赖与构建的依赖
    	}
    }
    export default config 
    

    二、关于环境的处理(生产/开发环境)

    vite.config.js()

    这里使用策略模式 分配开发环境和生产环境的不同配置

    Object.assign(target, …sources) 对象合并,将源对象中的属性复制到目标对象中,他将返回目标对象target。当对象中只有一级属性,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝(这一点和**展开运算符、**JSON.parse(JSON.stringify(obj))一样)

    import {defineConfig} from 'vite'
    import {viteDevConfig} from 'vite.dev.config.js'
    import {viteProdConfig} from 'vite.pro.config.js'
    import {viteBaseConfig} from 'vite.base.config.js'
    
    **//策略模式**
    const envResolver = {
        "build": ()=>Object.assign({},viteBaseConfig,viteProdConfig),//生产环境的依赖
        "serve": ()=>Object.assign({},viteBaseConfig,viteDevConfig),//开发环境的依赖
    }
    export default defineConfig((command:"build"|"serve")=>{
    	return envResolver[command]
    })
    

    vite.dev.config.js

    import {defineConfig} from 'vite'
    export default devConfig({
    	optimizeDeps:{
    		...
    	}
    })
    

    三、关于环境变量的处理

    根据当前代码环境(开发/测试/生产…)变化,产生变化的变量即环境变量


    vite中的环境变量处理:dotenv,这个内置的工具库会在项目运行时在项目目录中寻找.env文件并自动读取文件中的对应环境变量

    .env.development

    BASE_URL = 'https://abc'
    

    .env.production

    BASE_URL = 'https://abc'
    

    不会并将其注入到process对象下(node关于当前进程的一个对象(node全局),vite就是在node环境下运行的);

    原因:vite考虑到和其它配置的一些冲突问题,涉及到config.js中的一些配置项(为了防止冲突,环境变量不会直接放入,而是通过loadEnv手动确认导入,才进行放置。)

    -root

    -envDir(配置环境变量的文件地址)

    (vite考虑到congig配置中有可能更改环境变量文件地址,因此在这之前读取process就会是无意义的)

    vite提供的相关措施:调用vite的loadEnv来手动确认env文件(三个参数:mode,env目录,文件名)

    export default defineConfig((command:"build"|"serve",mode)=>{
    	const envProcess =  loadEnv(mode,process.cwd(),"") // process.cwd():node运行工作目录(顶层)
    	//	**loadEnv**来手动确认env文件后,会向envProcess 中注入环境变量,默认.env文件
    	
    return envResolver[command]
    })
    

    mode:例如npm run dev --mode development,则会将mode设置为development

    也就是说,mode会和后面的env文件名拼接,再根据目录去寻找对应环境下的环境变量文件!!

    然后将文件中的变量添加到envProcess 中(会将公共.env和另一个环境.env组合成一个新的)。

    .env:所有环境都需要用到的环境变量
    .env.development:开发环境(默认情况下)
    .env.production:生产环境

    上面讲的是服务端,如果是客户端,vite会寻找.env文件直接将对应的环境变量注入到**import.meta.env中,但是vite做了一个拦截,防止我们将一些隐私性的变量直接放到import.meta.env** 中,如果环境变量不是以 VITE_ 开头的,则不会注入到**import.meta.env ,**客户端获取不到,所以每个环境下的环境变量如果需要再客户端使用,需要加VITE_ 前缀,如果想要更改这个VITE_前缀,可以配置envPrefix

    import {defineConfig} from 'vite'
    export default devConfig({
    	optimizeDeps:{
    		...
    	},
    	envPrefix:"ENV" //客户端校验的环境变量名的默认前缀
    })
    

    四、vite中对css以及css模块化的处理、css配置

    • vite处理css文件
      1. vite读取到某个模块引用了css文件
      2. 用fs模块去读取css文件中的内容
      3. 创建一个style标签,将文件中的内容放进标签中
      4. 将style标签的直接插入到index.js的head中
      5. 将该css文件直接替换为js脚本(方便热更新或css模块化),同时设置该文件Content-type为js,让浏览器以js脚本的形式来执行css文件
    • 模块化(.module.css,module.sass)
      1. 是基于node的
      2. 读取文件,(.module)
      3. 将文件中的所有类名根据一定规则进行替换
      4. 同时创建一个映射对象{footer:_footer_d12_sda}
      5. 将替换后的内容放进style标签中在放到indexjs的head中
      6. 默认导出映射对象
      7. 将该css文件直接替换为js脚本(方便热更新或css模块化),同时设置该文件Content-type为js,让浏览器以js脚本的形式来执行css文件

    vite配置文件的css配置

    1、modules模块化相关

    通过配置css属性对css的行为进行相关配置

    • localsConvention——修改生成的配置对象的key的展示形式

    (“camelCase”:驼峰(驼峰和短横线都会显示) ;“camelCaseOnly”:只显示驼峰;“dashes”:短横线;“dashesOnly”)

    • scopeBehavior——配置当前模块化行为是模块化还是全局化

    (“local”-有哈希-模块化:可以保证产生不同的哈希值来保证样式不被覆盖;“global”-取消模块化(一般不用))

    • generateScopedName——生成的类名的规则/展示格式,也可以配置为函数

    ("[name][locat]**[hash:5]“)

    • hashPrefix——生成的哈希前缀
    • globalModulePaths——不想参与到css模块化的文件路径

    vite.config.js

    import {defineConfig} from 'vite'
    export default devConfig({
    	optimizeDeps:{
    		...
    	},
    	envPrefix:"ENV" //客户端校验的环境变量名的默认前缀,
    	css:{
    		modules:{//对css模块化的默认行为进行覆盖
    			localsConvention:"camelCase",
    			scopeBehavior:"local",
    			generateScopedName:"[name]_[locat]*_*[hash:5]",
    			hashPrefix:""
    
    		}
    	}
    })
    

    2、preprocessorOptions 预处理器相关

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

    vite.config.js

    import {defineConfig} from 'vite'
    export default devConfig({
    	optimizeDeps:{
    		...
    	},
    	envPrefix:"ENV" //客户端校验的环境变量名的默认前缀,
    	css:{
    		modules:{//对css模块化的默认行为进行覆盖
    			...
    		},
    		preprocessorOptions:{ //key+config
    			less:{
    				math:"always",
    				globalVars:{//全局变量
    					mainColor:"red",
    				}
    			},
    			sass:{},
    		},
    		devSorcemap:true //代码编译打包后出错,会定位到源文件出错的位置,默认为false
    	}
    })
    

    3、postcss

    postcss的相关配置,postcss—相当于less和sass的后处理器,解决它们解决不了的问题

    插件:postcss-preset-env: 支持css变量和一些未来css语法 自动补全(—webkit)

    如果没有在配置文件中写,会自动找到项目目录下的postcss.config.js文件

    vite.config.js

    import {defineConfig} from 'vite'
    import postcssPresetEnv from 'postcss-preset-env'
    export default devConfig({
    	optimizeDeps:{
    		...
    	},
    	envPrefix:"ENV" //客户端校验的环境变量名的默认前缀,
    	css:{
    		modules:{//对css模块化的默认行为进行覆盖
    			...
    		},
    		preprocessorOptions:{ //key+config
    			...
    		},
    		devSorcemap:true,//代码编译打包后出错,会定位到源文件出错的位置,默认为false
    		postcss:{
    			plugins:[**postcssPresetEnv()**]
    		}
    	}
    })
    

    五、vite对静态资源的处理及别名配置

    vite加载静态资源

    json,图片,svg,视频等都称为静态资源,vite对这些静态资源都是开箱即用的

    别名配置

    resolve下配置alias

    import {defineConfig} from 'vite'
    import postcssPresetEnv from 'postcss-preset-env'
    import path from 'path'
    export default devConfig({
    	resolve:{ //别名配置
    		alias:{
    			"@":path.resolve(__dirname,"./src"),
    			"@assets":path.resolve(__dirname,"./src/assets")
    		},
    	},
    	optimizeDeps:{
    		...
    	},
    	envPrefix:"ENV" //客户端校验的环境变量名的默认前缀,
    
    })
    

    原理:node服务器通过导入vite的配置对象,config.resolve.alias,得到别名和路径的键值对,当读取对象时,如果遇到**@时,会对其做字符串替换**,将切割后的路径替换进去

    vite配置文件中对静态资源在生产环境的一些配置

    在build配置项

    • rollupOptions- 配置rollup的一些构建策略
    • assetsInlineLimit - 如果图片小于4kb,则转为base64图片,大于4kb,转为静态资源文件
    • outDir- 打包输出的文件夹名
    • assetsDir- 打包输出的静态资源的文件夹名
    • emptyOutDir- 默认是true,打包时清楚上一次的打包输出目录

    打包后的静态资源有hash——浏览器会缓存相同文件名的文件,为避免每次打包出来的东西名字一致,所以vite默认打包后的资源文件名会根据一定规则加上hash(根据文件内容去生成hash) 利用这个hash算法,可以更好的去控制浏览器的 缓存机制

    vite.config.js

    import {defineConfig} from 'vite'
    import postcssPresetEnv from 'postcss-preset-env'
    import path from 'path'
    export default devConfig({
    	resolve:{ //别名配置
    		alias:{
    			"@":path.resolve(__dirname,"./src"),
    			"@assets":path.resolve(__dirname,"./src/assets")
    		},
    	},
    	optimizeDeps:{
    		...
    	},
    	envPrefix:...//客户端校验的环境变量名的默认前缀,
    	build:{
    		rollupOptions:{//配置rollup的一些构建策略(vite在打包时会将一些事情交给rollup处理)
    				output:{
    				//hash是由文件名和文件内容组合计算得来的结果
    				assetFileNames:"[hash].[name]"
    			}
    		},
    
    		assetsInlineLimit:4096 ,//如果图片小于4kb,则转为base64图片,大于4kb,转为静态资源文件
    		outDir:"Mydist",  //打包输出的文件夹名
    		assetsDir:"static",  // 打包输出的静态资源的文件夹名
    		emptyOutDir:true, //默认是true,打包时清楚上一次的打包输出目录
    	}
    
    })
    

    六、 vite插件

    插件是什么?

    vite会在不同的生命周期去调用不同的插件,以达到不同的目的

    vite从开始执行到结束就是其生命周期

    插件 API | Vite 官方中文文档 (vitejs.cn)

    中间件/插件作用?——在不同的生命周期去调用不同的插件/中间件,以达到不同的目的

    插件使用

    vite.config.js

    import vitePlugin from 'vite-plugin-feature'
    import rollupPlugin from 'rollup-plugin-feature'
    import {defineConfig} from 'vite'
    
    export default defineConfig({
      plugins: [vitePlugin(), rollupPlugin()]
    })
    

    vite插件钩子

    **config 配置之前

    **configResolved 整个配置文件解析流程完毕后调用

    **configureServer 服务器相关

    **configurePreviewServer 打包后生产环境预览相关

    **transformIndexHtml 转换 index.HTML相关

    **handleHotUpdate 热更新(自定义热更新行为)

    universal hooks (vite和rollup通用的钩子)

    options

    buildStart

    插件顺序

    一个 Vite 插件可以额外指定一个 enforce 属性(类似于 webpack 加载器)来调整它的应用顺序。enforce 的值可以是prepost。解析后的插件将按照以下顺序排列:

    • Alias
    • 带有 enforce: 'pre' 的用户插件
    • Vite 核心插件
    • 没有 enforce 值的用户插件
    • Vite 构建用的插件
    • 带有 enforce: 'post' 的用户插件
    • Vite 后置构建插件(最小化,manifest,报告)

    常用插件

    github插件列表

    1. vite-aliases

    帮助我们自动生成别名:检测你当前目录下包括src在内的所有文件夹,并帮助我们去生成别名

    1. vite-plugin-html

    转换 HTML 字符串

    1. vite-plugin-mock

    做mock数据:模拟数据

    mockjs,vite-plugin-mock的依赖项就是mockjs

    mock github文档:Getting Started · nuysoft/Mock Wiki (github.com)

    vite.config.js

    import vitePlugin from 'vite-plugin-feature'
    import rollupPlugin from 'rollup-plugin-feature'
    import {defineConfig} from 'vite'
    import {viteMockServe} from 'vite-plugin-mock'
    //
    export default defineConfig({
      plugins: [vitePlugin(), rollupPlugin(),viteMockServe()] 
    //viteMockServe会默认找到项目根目录中的mock文件
    })
    

    vite-plugin-mock插件的viteMockServe会默认找到项目根目录中的mock文件

    项目中就可以直接使用mock文件中配置的api地址并获取其中配置的返回数据

    • mock数据使用-mock

      Mock.mock( {
        // 属性 list 的值是一个数组,随机生成 1 到 10 个元素
        "userList|1-10": [
          {
            // 随机生成1-10个★
            "string|1-10": "★",
            // 随机生成1-100之间的任意整数
            "number|1-100": 1,
            // 生成一个浮点数,整数部分大于等于 1、小于等于 100,小数部分保留 1 到 10 位。
            "floatNumber|1-100.1-10": 1,
            // 随机生成一个布尔值,值为 true 的概率是 1/2,值为 false 的概率同样是 1/2。
            "boolean|1": true,
            // 随机生成一个布尔值,值为 false 的概率是 2 / (2 + 5),值为 true 的概率是 5 / (2 + 5)。
            'bool|2-5': false,
            // 从属性值 object 中随机选取 2-4 个属性
            "object|2-4": {
              "310000": "上海市",
              "320000": "江苏省",
              "330000": "浙江省",
              "340000": "安徽省"
            },
            // 通过重复属性值 array 生成一个新数组,重复次数为 2
            "array|2": [
              "AMD",
              "CMD",
              "UMD"
            ],
            // 执行函数 function,取其返回值作为最终的属性值,函数的上下文为属性 'name' 所在的对象。
            'foo': '哇哈哈哈哈',
            'name': function () {
              return this.foo
            },
            // 根据正则表达式 regexp 反向生成可以匹配它的字符串。用于生成自定义格式的字符串。
            'regexp': /\d{5,10}/,
      			"id|+1": 1,
      			"id1": Random.id(),
      			"string": Random.string(5), // "jPXEu"
            "string2": '@string(5)', // "jPXEu"
            // 生成随机邮箱地址 可以指定域名,例如 163.com
            "email": Random.email('163.com'), // "l.fvilfpz@163.com"
            "email2": '@email()', // "l.fvilfpz@163.com"
            // 返回一个随机的布尔值。
            "boolean": Random.boolean(), // true
            "boolean2": '@boolean()', // true
            // 生成 60-100 随机整数
            "point": Random.integer(60, 100), // 69
            "point2": '@integer(60, 100)', // 98
            // // 生成一个浮点数,整数部分大于等于 1、小于等于 100,小数部分保留 3 到 5 位。
            "floatNumber": Random.float(1, 100, 3, 5), // 60.695
            "floatNumber2": '@float(1, 100, 3, 5)', // 19.29368
            // 随机日期
            "date": Random.datetime('yyyy-MM-dd'), // "2017-05-01"
            "date2": "@datetime()", // "1973-06-12 13:05:18"
            // 随机时间
            "time": Random.time(), // "21:33:01"
            "time2": "@time()", // "21:33:01"
            // 当前日期
            "now": Random.now('year'), // "2023-01-01 00:00:00"
            "now2": "@now('year')", // "2023-01-01 00:00:00"
            // 随机生成图片 Random.image( size, background, foreground, format, text )
            "img": Random.image('200x100', '#16d46b', '#fff', 'png', 'Hello'), // "http://dummyimage.com/200x100/16d46b/fff.png&text=Hello"
            // 随机生成颜色,格式为 '#RRGGBB'。
            "color": Random.color(), // "#94f279"
            "color2": '@color()', // "#94f279"
            // 随机生成颜色,格式为 'rgb(r, g, b, a)'。
            "rgbaColor": Random.rgba(), // "rgba(242, 121, 183, 0.22)"
            // 随机生成一段文本 文本中句子的个数为 2 到 5。默认值为 3 到 7
            "paragraph": Random.paragraph(2, 5), // "Ymkp nvyryy vieq hlqdb pplbbikbd mtqiq uue jdufhkxy wpybjqi djico jxqkwvw kbmsscpfw owtgsqwn."
            "paragraph2": '@paragraph(2, 5)',  // "Ymkp nvyryy vieq hlqdb pplbbikbd mtqiq uue jdufhkxy wpybjqi djico jxqkwvw kbmsscpfw owtgsqwn."
            // 随机生成一段中文文本 参数同 Random.paragraph( min?, max? )
            "cparagraph": Random.cparagraph(), // "重工边政应信江半实金改北反调程五八。张资圆向规成新家天交对传许。军较军七养多认维市般况验式华行证。"
            "cparagraph2": '@cparagraph(2, 5)', // "重工边政应信江半实金改北反调程五八。张资圆向规成新家天交对传许。军较军七养多认维市般况验式华行证。"
            // 随机生成一个句子,第一个单词的首字母大写。 句子中单词的个数为 2 到 5 。默认值为 12 到 18
            "sentence": Random.sentence(2, 5), // "Yyfvs genrdeiyf."
            "sentence2": '@sentence(2, 5)', // "Yyfvs genrdeiyf."
            // 随机生成一段中文文本,参数同 Random.sentence( min?, max? )
            "csentence": Random.csentence(2, 5), // "积现。"
            "csentence2": '@csentence(2, 5)', // "积现。"
            // 随机生成一个单词,单词中字符的个数为 2 到 5 个。默认值为 3 到 10
            "word": Random.word(2, 5), // "nlgcl"
            "word2": '@word(2, 5)', // "nlgcl"
            // 随机生成一个汉字,汉字中字符串的长度为 2 到 5 个。默认值为 1
            "cword": Random.cword(2, 5), // "系即感"
            "cword2": '@cword(2, 5)', // "系即感"
            // 随机生成一句标题,其中每个单词的首字母大写。单词中字符的个数为 2 到 5。默认值为 3 到 7
            "title": Random.title(2, 5), // "Vmpx Rizds Smguoqki"
            "title2": '@title(2, 5)', // "Vmpx Rizds Smguoqki"
            // 随机生成一句中文标题,参数同 Random.title( min?, max? )
            "ctitle": Random.ctitle(2, 5), // "其感期"
            "ctitle2": '@ctitle(2, 5)', // "其感期"
            // 随机生成一个常见的英文名
            "firstName": Random.first(), // "Michelle"
            "firstName2": '@first()', // "Jose"
            // 随机生成一个常见的英文姓。
            "lastName": Random.last(), // "Taylor"
            "lastName2": '@last()', // "Clark"
            // 随机生成一个常见的英文姓名。括号里的布尔值,指示是否生成中间名(可选)。
            "name": Random.name(true), // "Donald Eric Jackson"
            "name2": '@name(true)', // "Donald Eric Jackson"
            // 随机生成一个常见的中文姓
            "cfirstName": Random.cfirst(), // "任"
            "cfirstName2": '@cfirst()', // "郭"
            // 随机生成一个常见的中文名。
            "clastName": Random.clast(), // "芳"
            "clastName2": '@clast()', // "芳"
            // 随机生成一个常见的中文姓名。
            "cname": Random.cname(), // "程强"
            "cname2": '@cname()', // "程强"
            // 随机生成一个URL。可以指定url协议,域名和端口号。例如'http' nuysoft.com。
            'url': Random.url('http', 'nuysoft.com'), // "http://nuysoft.com/ysq"
            'url2': '@url()', // "http://nuysoft.com/ysq"
            // 随机生成一个 IP 地址
            'IP': Random.ip(), // "112.127.151.37"
            'IP2': '@ip()', // "233.144.17.219"
            // 随机生成一个(中国)大区。
            "region": Random.region(), // "华北"
            "region2": '@region()', // "华北"
            // 随机生成一个(中国)省(或直辖市、自治区、特别行政区)。
            "province": Random.province(), // "澳门特别行政区"
            "province2": '@province()', // "澳门特别行政区"
            // 随机生成一个(中国)市。括号里的布尔值,指是否生成所属的省(可选)
            "city": Random.city(true), // "广东省 肇庆市"
            "city2": '@city()', // "广东省 肇庆市"
            // 随机生成一个(中国)县。括号里的布尔值,指是否生成所属的省、市(可选)
            "county": Random.county(true), // "江苏省 常州市 其它区"
            "county2": '@county()', // "江苏省 常州市 其它区"
            // 随机生成一个邮政编码(六位数字)。
            "zip": Random.zip(), // "806124"
            "zip2": '@zip()', // "806124"
            // 把字符串的第一个字母转换为大写。
            "capitalize": Random.capitalize('hello'), // "Hello"
            "capitalize2": '@capitalize("hello")', // "Hello"
            // 把字符串转换为大写。
            "upper": Random.upper('hello'), // "HELLO"
            "upper2": '@upper("hello")',  // "HELLO"
            // 把字符串转换为小写。
            "lower": Random.lower('HELLO'), // "hello"
            "lower2": '@lower("HELLO")', // "hello"
            // 从数组中随机选取一个元素并返回。
            "pick": Random.pick(['a', 'e', 'i', 'o', 'u']), // "e"
            "pick2": '@pick(["a", "e", "i", "o", "u"])', // "e"
            // 打乱数组中元素的顺序,并返回。
            "shuffle": Random.shuffle(['a', 'e', 'i', 'o', 'u']), // ['o', 'a', 'i', 'e', 'u']
            "shuffle2": '@shuffle(["a", "e", "i", "o", "u"])', // ['o', 'a', 'i', 'e', 'u']
            // 随机生成一个 18 位身份证。
            "id": Random.id(), // 112.127.151.37
            "id2": '@id()' // 97.46.129.222
      
      ————————————————
      csdn原文链接:https://blog.csdn.net/Mme061300/article/details/130343270
          },
        ],
      })
      

    mock/index.js

    import Mock from 'mock'
    export const userData = Mock.mock( {
      // 属性 userList的值是一个数组,随机生成 1 到 10 个元素
      "userList|1-10": [
        {
          // 随机生成1-10个★
          "name": "@cname",
    			...
        },
      ],
    })
    ————————————————
    
    export default = ([
      // 命中 /api/test?a=1
      {
    		method:"get"
        url: '/api/test',
        validator: {
          query: {
            a: 1
          }
        },
        body: {
          message: 'query.a === 1'
        },
    		response:()=>{
    			return {
    				msg:"sucess",
    				code:200,
    				data:userData
    			}
    		}
      },
      // 命中 /api/test/abc
      {
        url: '/api/test/abc',
        body: {
          message: 'query.a === 2'
        }
      },
    
    ])
    

    vite与ts的结合

    Vite 天然支持引入 .ts 文件。

    功能 | Vite 官方中文文档 (vitejs.cn)

    Vite 仅执行 .ts 文件的转译工作,并 执行任何类型检查(只编译,不会执行类型检查)

    Vite 使用 esbuild 将 TypeScript 转译到 JavaScript

    所以如果想要在打包构建时进行类型检查,可以在 构建脚本中运行 tsc --noEmit ,即:

    //package.json
    "scripts"{
    	"build""tsc --noEmit && vite build"
    }
    

    如果需要ts类型报错提示,需要安装插件

    vite-plugin-checker

    npm i vite-plugin-checker -D

    npm i typescript -D

    使用ts需要有一个tsconfig.json文件配置一些ts的检查手段和检查规则

    vite.config.js

    
    import checker from 'vite-plugin-checker'
    import {defineConfig} from 'vite'
    
    export default defineConfig({
      plugins: [checker ({
    		typescript:true	
    	}),]
    })
    

    tsconfig.json

    //配置一些ts的检查手段和检查规则
    {
    	"compilerOptions":{
    		"skipLibCheck": ture,//·是否跳过node_modules目录的验查
    		"module":"ESNext"  //配置
    	}
    }
    

    typescript使用环境变量时,tsconfig.json默认es语法是es3,无法识别import.meta.env,所以需要在配置文件中配置"module"为"ESNext"

    至此,在ts文件中再引用import.meta.env,但还是出现报错,原因是:

    Vite 默认的类型定义是写给它的 Node.js API 的。要将其补充到一个 Vite 应用的客户端代码环境中,请添加一个 d.ts 声明文件:

    需要一个声明文件vite-env.d.ts

    //vite-env.d.ts
    //三斜线指令
    
    /// <reference types="vite/client" />
    
    interface ImportMetaEnv {//能让环境变量有提示(可有可无)
    	readonly VITE_PROXY_TARGET: string;
    }
    
    

    同时,将 vite/client 添加到 tsconfig 中的 compilerOptions.types 下:

    
    //配置一些ts的检查手段和检查规则
    {
    	"compilerOptions":{
    		"moduleResolution":"node",
    		"skipLibCheck": ture,//·是否跳过node_modules目录的验查
    		"module":"ESNext",  //配置
    		"types": ["vite/client"],
    		"lib":["ES2017","DOM"], // 配置es版本
    	}
    }
    

    这将会提供以下类型定义补充:

    • 资源导入 (例如:导入一个 .svg 文件)
    • import.meta.env 上 Vite 注入的环境变量的类型定义
    • import.meta.hot 上的 HMR API 类型定义

    vite性能优化(也是前端主要的性能优化)

    • 开发时的构建速度优化,即启动时间

    -vite是按需加载,所以不需要太关注这个

    • 页面性能指标(与代码有关)

    -首屏渲染时长 fcp(first content paint →页面中第一个元素的渲染时长)

    -懒加载

    -http优化(协商缓存,强缓存彻底弄懂强缓存与协商缓存 - 简书 (jianshu.com)

    index.html文件采用协商缓存,理由就是要用户每次请求index.html不拿浏览器缓存,直接请求服务器,这样就保证资源更新了,用户能马上访问到新资源,如果服务端返回304,说明资源没有更新,这时候再拿浏览器的缓存的index.html

    -页面中最大元素的渲染时长 lcp(largest content paint)

    • js逻辑

    **-**副作用的清除(组件挂载渲染时清除副作用)

    -写法上的一些注意事项,例如requestAnimationFrame,requestIdleCallback,这两个API主要用来 卡浏览器帧率

    -requestIdleCallback: 传一个回调函数进去,如果再16.6ms内执行完有剩余时间则会执行回调
    -浏览器的帧率: 16.6ms去更新一次 (执行js 以及 重排重绘…)

    -react concurrent mode ,react18 concurrency 可终端渲染

    -防抖、节流等,最好还是用工具库lodash,因为它是最佳实践;数组forEach 如果数据较大,建议也用lodash提供的forEach

    -作用域的控制

    for(let i = 0,len = arr.length,i<len,i++){ }

    • CSS

    –关注继承属性,能继承就不要重读写

    -尽量避免css嵌套过深

    -尽量减少重排重绘

    • 构建优化vite(rollup)

    -优化体积: ↓↓↓↓压缩,treeshaking,图片资源压缩,cdn加载,分包… ↓↓ ↓↓ ↓↓

    vite性能优化(构建部分)

    一、分包策略

    分包 就是把一些不会常规更新的代码进行单独打包处理

    例如:lodash库的一些代码在打包时是不会变的,但每次打包都需要重新构建,为优化这种情况,可以将这些不会常规更新的代码进行单独打包处理

    vite内部其实已经内置好了,自动优化了这些分包策略


    二、gzip压缩

    文件资源过大,影响http传输,将静态资源进行压缩,以达到减小体积的目的

    vite服务端-收到文件,进行压缩

    客户端-收到压缩后的文件,进行解压缩

    插件:vite-plugin-compression

    配置即可,打包后会生成.zp 文件,服务端会做相应配置,在读取到zp文件时会将其解压缩,这个过程也会消耗一些时间,所以如果体积不是很大,就不用使用gzip压缩,否则可能适得其反


    三、动态导入

    webpack - vite

    vite是按需加载的,webpack在构建时会将全部依赖加载

    动态导入 与 按需加载 类似 ,动态导入时es6的新特性

    代码分割

    import ("a.js").then(res=>{con`在这里插入代码片`sole.log(res)})
    

    动态导入后,打包后的代码,会将动态导入的代码分割开来

    动态导入路由

    routes:[
    	{`在这里插入代码片`
    		path:'/home'
    		component:import ("a.js"),
    	}
    ]
    

    四、CDN加速(content delivery network 内容分发网络)

    将项目依赖的代码全部写成cdn的形式,保证代码的小体积


    vite处理跨域问题

    不满足同源策略(协议、域名、端口任意一个不相同,仅发生在浏览器)

    更多开发服务器配置

    //vite处理跨域
    import {defineConfig} from 'vite'
    
    export default defineConfig({
    	server:{
    		proxy:{
    			// 使用 proxy 实例
          '/api': { //key+描述对象,遇到'`在这里插入代码片`/api'开头的请求时,都会将其代理到target属性对应的地址
            target: 'http://jsonplaceholder.typicode.com',
            changeOrigin: true,
    				rewrite: (path) => path.replace(/^\/api/, ''), //路径重写,将'api换成空串'
            
    				//configure: (proxy, options) => {
              // proxy 是 'http-proxy' 的实例
            //}
          },
    		}
    	}
    })
    

    即客户端去请求vite的开发服务器,服务器收到请求,根据config代理配置重写请求路径,从服务端发送请求,由于同源策略仅发生在浏览器,服务器端之间的请求不会受限制,所以vite开发服务器收到请求后,向重写后的地址发送请求,直接把相应结果给到浏览器(客户端)——当然以上都是关于开发环境的跨域解决

    生产环境——一般是交给后端或运维去处理跨域 -ngnix:代理服务(与本地开发服务器类似) / -配置身份标记(Access-Control-Allow-Origin)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值